ฉันใช้JSLintกับไฟล์ JavaScript ของฉัน มันโยนข้อผิดพลาด:
for( ind in evtListeners ) {
ปัญหาที่บรรทัดที่ 41 อักขระ 9: เนื้อหาของ a for in ควรถูกห่อด้วยคำสั่ง if เพื่อกรองคุณสมบัติที่ไม่ต้องการออกจากต้นแบบ
สิ่งนี้หมายความว่า?
ฉันใช้JSLintกับไฟล์ JavaScript ของฉัน มันโยนข้อผิดพลาด:
for( ind in evtListeners ) {
ปัญหาที่บรรทัดที่ 41 อักขระ 9: เนื้อหาของ a for in ควรถูกห่อด้วยคำสั่ง if เพื่อกรองคุณสมบัติที่ไม่ต้องการออกจากต้นแบบ
สิ่งนี้หมายความว่า?
คำตอบ:
ก่อนอื่นอย่าใช้การfor in
วนซ้ำเพื่อระบุค่าในอาร์เรย์ ไม่เคย for(var i = 0; i<arr.length; i++)
ใช้ดีเก่า
เหตุผลที่อยู่เบื้องหลังนี้คือต่อไปนี้: วัตถุใน JavaScript prototype
แต่ละคนมีข้อมูลพิเศษที่เรียกว่า ทุกสิ่งที่คุณเพิ่มลงในเขตข้อมูลนั้นจะสามารถเข้าถึงได้บนวัตถุทุกประเภทนั้น สมมติว่าคุณต้องการให้อาร์เรย์ทั้งหมดมีฟังก์ชั่นใหม่ที่เรียกfilter_0
ว่าจะกรองเลขศูนย์ออก
Array.prototype.filter_0 = function() {
var res = [];
for (var i = 0; i < this.length; i++) {
if (this[i] != 0) {
res.push(this[i]);
}
}
return res;
};
console.log([0, 5, 0, 3, 0, 1, 0].filter_0());
//prints [5,3,1]
นี่เป็นวิธีมาตรฐานในการขยายวัตถุและเพิ่มวิธีการใหม่ ห้องสมุดจำนวนมากทำเช่นนี้ อย่างไรก็ตามเรามาดูวิธีการfor in
ทำงานตอนนี้:
var listeners = ["a", "b", "c"];
for (o in listeners) {
console.log(o);
}
//prints:
// 0
// 1
// 2
// filter_0
คุณเห็นไหม? ทันใดนั้นคิดว่า filter_0 เป็นดัชนีอาเรย์อีกตัวหนึ่ง แน่นอนมันไม่ได้เป็นดัชนีที่เป็นตัวเลขจริงๆ แต่จะfor in
แจกแจงผ่านฟิลด์วัตถุไม่ใช่แค่ดัชนีที่เป็นตัวเลข ตอนนี้เรากำลังแจงนับผ่านดัชนีและ ตัวเลขทุกfilter_0
ตัว แต่filter_0
ไม่ได้เป็นเขตข้อมูลของวัตถุอาร์เรย์ใด ๆ ทุกวัตถุอาร์เรย์มีคุณสมบัตินี้ในขณะนี้
โชคดีที่วัตถุทั้งหมดมีhasOwnProperty
วิธีการซึ่งจะตรวจสอบว่าเขตข้อมูลนี้เป็นของวัตถุจริงๆหรือถ้ามันสืบทอดมาจากสายโซ่ต้นแบบและทำให้เป็นของวัตถุทั้งหมดของประเภทนั้น
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
โปรดทราบว่าแม้ว่ารหัสนี้จะทำงานตามที่คาดไว้สำหรับอาร์เรย์คุณไม่ควรใช้ไม่เคยใช้for in
และfor each in
สำหรับอาร์เรย์ โปรดจำไว้ว่าการfor in
แจกแจงเขตข้อมูลของวัตถุไม่ใช่ดัชนีอาร์เรย์หรือค่า
var listeners = ["a", "b", "c"];
listeners.happy = "Happy debugging";
for (o in listeners) {
if (listeners.hasOwnProperty(o)) {
console.log(o);
}
}
//prints:
// 0
// 1
// 2
// happy
for in
เพื่อย้ำผ่านอาร์เรย์เพราะภาษาไม่ได้การันตีลำดับที่for in
จะแจกแจงอาร์เรย์ มันอาจไม่อยู่ในลำดับที่เป็นตัวเลข นอกจากนี้หากคุณใช้ `สำหรับ (i = 0; ฉัน <array.length ผม ++) สร้างสไตล์ที่คุณสามารถแน่ใจว่าคุณเพียงคุณสมบัติวนดัชนีตัวเลขในการสั่งซื้อและไม่มีตัวอักษรและตัวเลข
for-in
ลูป (ซึ่งยอดเยี่ยมมาก) เราควรให้ความรู้แก่พวกเขาเกี่ยวกับวิธีการทำงาน (ทำอย่างถูกต้องในคำตอบนี้) และแนะนำพวกเขาเพื่อObject.defineProperty()
ให้พวกเขาสามารถขยายต้นแบบของพวกเขาได้อย่างปลอดภัย อนึ่งต้นแบบขยายวัตถุพื้นเมืองควรไม่Object.defineProperty
ทำได้โดยไม่ต้อง
Douglas Crockford ผู้เขียน jslint ได้เขียน (และพูด) เกี่ยวกับปัญหานี้หลายครั้ง มีส่วนหนึ่งในหน้านี้ของเว็บไซต์ซึ่งครอบคลุมสิ่งนี้:
สำหรับงบ
A สำหรับคลาสของ statement ควรมีแบบฟอร์มต่อไปนี้:
for (initialization; condition; update) { statements } for (variable in object) { if (filter) { statements } }
แบบฟอร์มแรกควรใช้กับอาร์เรย์และวนซ้ำของจำนวนการวนซ้ำที่กำหนดไว้ล่วงหน้า
ควรใช้แบบฟอร์มที่สองกับวัตถุ โปรดระวังว่าสมาชิกที่เพิ่มเข้ากับต้นแบบของวัตถุจะถูกรวมไว้ในการแจงนับ ขอแนะนำให้โปรแกรมตั้งรับโดยใช้วิธีการ hasOwnProperty เพื่อแยกความแตกต่างสมาชิกที่แท้จริงของวัตถุ:
for (variable in object) { if (object.hasOwnProperty(variable)) { statements } }
คร็อคฟอร์ดยังมีซีรีย์วิดีโอเกี่ยวกับโรงละคร YUI ที่ซึ่งเขาพูดถึงเรื่องนี้ วิดีโอ / การพูดถึงชุดของ Crockford เกี่ยวกับจาวาสคริปต์ต้องดูว่าคุณจริงจังกับจาวาสคริปต์หรือไม่
ไม่ดี: (jsHint จะโยนข้อผิดพลาด)
for (var name in item) {
console.log(item[name]);
}
ดี:
for (var name in item) {
if (item.hasOwnProperty(name)) {
console.log(item[name]);
}
}
คำตอบของ Vava อยู่ที่เครื่องหมาย หากคุณใช้ jQuery $.each()
ฟังก์ชันจะดูแลสิ่งนี้ดังนั้นจึงปลอดภัยกว่าที่จะใช้
$.each(evtListeners, function(index, elem) {
// your code
});
$.each
(หรือ underscore.js _.each
) หากคุณสามารถหลีกเลี่ยงการfor
วนซ้ำดิบ jsperf มีการทดสอบการเปรียบเทียบแบบเปิดหูเปิดตาที่น่าใช้งาน
@all - ทุกอย่างใน JavaScript เป็นวัตถุ () ดังนั้นคำสั่งเช่น "ใช้เฉพาะสิ่งนี้กับวัตถุ" เป็นการทำให้เข้าใจผิด นอกจากนี้ยังไม่ได้พิมพ์ JavaScript อย่างยิ่งเพื่อให้ 1 == "1" เป็นจริง (แม้ว่า 1 === "1" ไม่เป็นเช่นนั้น Crockford มีขนาดใหญ่ในเรื่องนี้) เมื่อพูดถึงแนวคิดของอาร์เรย์ใน progromatic ใน JS การพิมพ์มีความสำคัญในคำจำกัดความ
@Brenton - ไม่จำเป็นต้องเป็นเผด็จการศัพท์ "อาเรย์ร่วม", "พจนานุกรม", "แฮช", "วัตถุ" แนวคิดการเขียนโปรแกรมเหล่านี้ทั้งหมดนำไปใช้กับหนึ่งโครงสร้างใน JS เป็นคู่ของชื่อ (คีย์, ดัชนี) ที่ค่าสามารถเป็นวัตถุอื่นได้ (สตริงเป็นวัตถุด้วย)
ดังนั้น
new Array()
เป็นเช่นเดียวกับ[]
new Object()
คล้าย ๆ กับ {}
var myarray = [];
สร้างโครงสร้างที่เป็นอาร์เรย์ที่มีข้อ จำกัด ที่ดัชนีทั้งหมด (คีย์ aka) ต้องเป็นจำนวนเต็ม นอกจากนี้ยังช่วยให้การกำหนดดัชนีใหม่โดยอัตโนมัติผ่าน. พุช ()
var myarray = ["one","two","three"];
เป็นทางเลือกที่ดีที่สุด for(initialization;condition;update){
แต่สิ่งที่เกี่ยวกับ:
var myarray = [];
myarray[100] = "foo";
myarray.push("bar");
ลองสิ่งนี้:
var myarray = [], i;
myarray[100] = "foo";
myarray.push("bar");
myarray[150] = "baz";
myarray.push("qux");
alert(myarray.length);
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}
อาจไม่ใช่การใช้งานอาร์เรย์ที่ดีที่สุด แต่เป็นเพียงภาพประกอบที่สิ่งต่าง ๆ ไม่ถูกตัดออกไปเสมอ
หากคุณรู้ว่ากุญแจของคุณและแน่นอนว่าถ้าพวกเขาไม่ใช่ตัวเลขทั้งหมดตัวเลือกอาร์เรย์เช่นเดียวกับโครงสร้างของคุณคือวัตถุ
var i, myarray= {
"first":"john",
"last":"doe",
100:"foo",
150:"baz"
};
for(i in myarray){
if(myarray.hasOwnProperty(i)){
alert(i+" : "+myarray[i]);
}
}
แน่นอนมันสุดโต่งที่จะพูด
... อย่าใช้ a ในวงวนเพื่อแจกแจงอาร์เรย์ ไม่เคย ใช้ค่าเก่าสำหรับ (var i = 0; i <arr.length; i ++)
?
การเน้นส่วนในสารสกัด Douglas Crockford นั้นคุ้มค่า
... ควรใช้แบบฟอร์มที่สองกับวัตถุ ...
หากคุณต้องการอาเรย์ (aka Hashtable พจนานุกรม /) var myAssocArray = {key1: "value1", key2: "value2"...};
ที่คีย์จะถูกตั้งชื่อแทนการจัดทำดัชนีตัวเลขที่คุณจะต้องดำเนินการนี้เป็นวัตถุเช่น
ในกรณีนี้myAssocArray.length
จะเกิดขึ้นเป็นโมฆะ (เนื่องจากวัตถุนี้ไม่มีคุณสมบัติ 'ความยาว') และคุณi < myAssocArray.length
จะไม่ทำให้คุณไปได้ไกลนัก นอกเหนือจากการอำนวยความสะดวกที่มากขึ้นฉันคาดหวังว่าอาเรย์แบบเชื่อมโยงจะเสนอข้อได้เปรียบด้านประสิทธิภาพในหลาย ๆ สถานการณ์เนื่องจากคีย์อาเรย์อาจเป็นคุณสมบัติที่มีประโยชน์ (เช่นคุณสมบัติ ID หรือชื่อสมาชิกอาเรย์ของสมาชิกอาเรย์) array ประเมินซ้ำ ๆ ว่า statement เพื่อค้นหารายการ array ที่อยู่หลัง
อย่างไรก็ตามขอขอบคุณสำหรับคำอธิบายของข้อความแสดงข้อผิดพลาด JSLint ฉันจะใช้การตรวจสอบ 'isOwnProperty' ตอนนี้เมื่อทำการเชื่อมต่อผ่านอาร์เรย์ที่เชื่อมโยงมากมายของฉัน!
length
ทรัพย์สิน แต่คุณสามารถทำอย่างอื่นได้:var myArr = []; myArr['key1'] = 'hello'; myArr['key2'] = 'world';
var myArr = []
มันควรอยู่var myArr = {}
ใน PHP มันเหมือนกัน แต่ไม่ใช่ใน JS
ซึ่งหมายความว่าคุณควรจะกรองคุณสมบัติของ evtListeners กับวิธี hasOwnProperty
เพียงเพื่อเพิ่มในหัวข้อสำหรับใน / สำหรับ / $ แต่ละฉันเพิ่มกรณีทดสอบ jsperf สำหรับการใช้ $ .each vs สำหรับใน: http://jsperf.com/each-vs-for-in/2
เบราว์เซอร์ / รุ่นที่แตกต่างกันจัดการมันแตกต่างกัน แต่ดูเหมือนว่า $ .each และตรงไปตรงมาเป็นตัวเลือกที่ประหยัดที่สุด
หากคุณกำลังใช้ในในการวนซ้ำผ่านอาร์เรย์ / วัตถุที่เชื่อมโยงรู้ว่าคุณเป็นใครและไม่สนใจสิ่งอื่นใดให้ใช้ $. แต่ละครั้งถ้าคุณใช้ jQuery หรือเพียงแค่ใช้ใน (และจากนั้นพักเมื่อคุณได้ ถึงสิ่งที่คุณรู้ว่าควรเป็นองค์ประกอบสุดท้าย)
หากคุณทำซ้ำอาร์เรย์เพื่อดำเนินการบางอย่างกับแต่ละคู่คีย์ในนั้นควรใช้วิธี hasOwnProperty หากคุณไม่ใช้ jQuery และใช้ $ .each ถ้าคุณใช้ jQuery
ใช้ทุกครั้งfor(i=0;i<o.length;i++)
หากคุณไม่ต้องการอาเรย์แบบเชื่อมโยงแม้ว่า ... lol chrome ทำงานได้เร็วกว่า 97% ในหรือ$.each
if (evtListeners.hasOwnProperty(ind))
เพื่อ จำกัด การประมวลผลเฉพาะคุณสมบัติ (ไม่สืบทอด) เท่านั้น อย่างไรก็ตามในบางกรณีคุณต้องการทำซ้ำกับคุณสมบัติทั้งหมดรวมถึงคุณสมบัติที่สืบทอดมา ในกรณีนั้น JSLint จะบังคับให้คุณตัดส่วนของลูปในคำสั่ง if เพื่อตัดสินใจว่าคุณสมบัติใดที่คุณต้องการจริงๆ สิ่งนี้จะใช้งานได้และทำให้ JSlint มีความสุข:if (evtListeners[ind] !== undefined)