ฉันรู้ว่ามันใช้เพื่อทำให้อาร์กิวเมนต์เป็นอาร์เรย์จริง แต่ฉันไม่เข้าใจว่าเกิดอะไรขึ้นเมื่อใช้ Array.prototype.slice.call(arguments)
ฉันรู้ว่ามันใช้เพื่อทำให้อาร์กิวเมนต์เป็นอาร์เรย์จริง แต่ฉันไม่เข้าใจว่าเกิดอะไรขึ้นเมื่อใช้ Array.prototype.slice.call(arguments)
คำตอบ:
สิ่งที่เกิดขึ้นภายใต้ประทุนคือเมื่อ.slice()
ถูกเรียกตามปกติแล้วthis
ก็คืออาเรย์
เป็นวิธีการthis
ใน.slice()
การทำงานของอาร์เรย์? เพราะเมื่อคุณ:
object.method();
ที่ ... object
จะกลายเป็นค่าของโดยอัตโนมัติในthis
method()
ดังนั้นด้วย:
[1,2,3].slice()
ที่ ... [1,2,3]
อาร์เรย์ถูกตั้งค่าเป็นค่าของในthis
.slice()
แต่ถ้าคุณสามารถทดแทนสิ่งอื่นเป็นthis
ค่าได้ ตราบใดที่สิ่งที่คุณแทนที่มี.length
คุณสมบัติเป็นตัวเลขและมีคุณสมบัติมากมายที่เป็นดัชนีตัวเลขก็ควรใช้งานได้ ชนิดของวัตถุนี้มักจะถูกเรียกว่าวัตถุอาร์เรย์เหมือน
.call()
และ.apply()
วิธีการให้คุณด้วยตนเองกำหนดค่าของการthis
ในการทำงาน ดังนั้นถ้าเราตั้งค่าของthis
ใน.slice()
สระอาร์เรย์เหมือนวัตถุ , .slice()
ก็จะถือว่ามันทำงานกับอาร์เรย์และจะทำสิ่งที่ตน
นำวัตถุธรรมดานี้เป็นตัวอย่าง
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
เห็นได้ชัดว่าไม่ใช่ Array แต่ถ้าคุณสามารถตั้งค่าเป็นthis
ค่าของ.slice()
มันก็จะทำงานได้เพราะมันดูเหมือน Array สำหรับ.slice()
การทำงานอย่างถูกต้อง
var sliced = Array.prototype.slice.call( my_object, 3 );
ตัวอย่าง: http://jsfiddle.net/wSvkv/
ดังที่คุณเห็นในคอนโซลผลลัพธ์คือสิ่งที่เราคาดหวัง:
['three','four'];
ดังนั้นนี่คือสิ่งที่เกิดขึ้นเมื่อคุณกำหนดarguments
วัตถุที่เป็นค่าของthis
.slice()
เนื่องจากarguments
มี.length
คุณสมบัติและดัชนีตัวเลขจำนวนหนึ่ง.slice()
เพียงแค่ทำงานเกี่ยวกับมันราวกับว่ามันทำงานในอาร์เรย์ที่แท้จริง
Array.prototype.slice
คำอธิบายวิธีการ
for-in
คำสั่งที่ไม่รับประกันการสั่งซื้อ อัลกอริทึมที่ใช้โดย.slice()
กำหนดลำดับตัวเลขเริ่มต้นด้วย0
และสิ้นสุด (ไม่รวม) กับ.length
วัตถุที่กำหนด (หรือ Array หรืออะไรก็ตาม) ดังนั้นคำสั่งนั้นรับประกันว่าจะสอดคล้องกันในทุกการใช้งาน
var obj = {2:"two", 0:"zero", 1: "one"}
สมมติว่าผมมี ถ้าเราใช้for-in
เพื่อระบุวัตถุไม่มีการรับประกันการสั่งซื้อ แต่ถ้าเราใช้เราด้วยตนเองสามารถบังคับใช้คำสั่ง:for
for (var i = 0; i < 3; i++) { console.log(obj[i]); }
ตอนนี้เรารู้แล้วว่าคุณสมบัติของวัตถุจะไปถึงลำดับตัวเลขที่เรากำหนดโดยfor
ลูปของเรา นั่นคือสิ่งที่.slice()
ทำ มันไม่สนใจว่ามันมีอาร์เรย์จริงหรือไม่ มันเพิ่งเริ่มต้น0
และเข้าถึงคุณสมบัติในลูปจากน้อยไปมาก
arguments
วัตถุไม่จริงเป็นตัวอย่างของอาร์เรย์และไม่ได้มีวิธีการใด ๆ อาร์เรย์ ดังนั้น,arguments.slice(...)
จะไม่ทำงานเพราะวัตถุข้อโต้แย้งไม่มีวิธีการแบ่งส่วน
อาร์เรย์มีวิธีการนี้และเนื่องจากarguments
วัตถุคล้ายกับอาร์เรย์ทั้งสองจึงเข้ากันได้ ซึ่งหมายความว่าเราสามารถใช้วิธีการอาร์เรย์กับวัตถุข้อโต้แย้ง และเนื่องจากวิธีการอาร์เรย์ถูกสร้างขึ้นโดยมีอาร์เรย์อยู่ในใจพวกเขาจะกลับอาร์เรย์มากกว่าวัตถุอาร์กิวเมนต์อื่น ๆ
เหตุใดจึงต้องใช้Array.prototype
? Array
เป็นวัตถุที่เราสร้างอาร์เรย์ใหม่จาก ( new Array()
) และเหล่าอาร์เรย์ใหม่จะถูกส่งผ่านวิธีการและคุณสมบัติเช่นชิ้น วิธีการเหล่านี้ถูกเก็บไว้ใน[Class].prototype
วัตถุ ดังนั้นเพื่อประสิทธิภาพอย่างมีประสิทธิภาพแทนที่จะเข้าถึงวิธีการแบ่งส่วนด้วยวิธี(new Array()).slice.call()
หรือ[].slice.call()
เราแค่นำมันมาจากต้นแบบโดยตรง นี่คือเพื่อให้เราไม่ต้องเริ่มต้นอาร์เรย์ใหม่
แต่ทำไมเราต้องทำสิ่งนี้ตั้งแต่แรก? อย่างที่คุณบอกว่ามันจะแปลงอ็อบเจกต์อาร์กิวเมนต์เป็น Array instance อย่างไรก็ตามสาเหตุที่เราใช้ส่วนแบ่งเป็น "แฮ็ค" มากกว่าสิ่งใด วิธีการแบ่งจะใช้เวลาคุณเดามันฝานของอาร์เรย์และคืนชิ้นนั้นเป็นอาร์เรย์ใหม่ การส่งผ่านข้อโต้แย้งไม่มี (นอกเหนือจากวัตถุอาร์กิวเมนต์เป็นบริบท) ทำให้วิธีการแบ่งเต็มของอาร์เรย์ "ผ่าน" (ในกรณีนี้วัตถุอาร์กิวเมนต์) และส่งคืนเป็นอาร์เรย์ใหม่
โดยปกติการโทร
var b = a.slice();
จะคัดลอกอาร์เรย์เข้าa
b
อย่างไรก็ตามเราทำไม่ได้
var a = arguments.slice();
เพราะarguments
ไม่ใช่อาเรย์ที่แท้จริงและไม่มีslice
วิธีการ Array.prototype.slice
เป็นslice
ฟังก์ชั่นสำหรับอาร์เรย์และcall
ทำงานฟังก์ชั่นที่มีการกำหนดให้this
arguments
prototype
? ไม่ได้เป็นslice
ชาวArray
วิธี?
Array
เป็นฟังก์ชั่นคอนสตรัคและสอดคล้องกัน "ชั้น" Array.prototype
คือ คุณสามารถใช้[].slice
slice
เป็นวิธีการของแต่ละArray
อินสแตนซ์ แต่ไม่ใช่Array
ฟังก์ชันตัวสร้าง คุณใช้prototype
เพื่อเข้าถึงวิธีการของอินสแตนซ์ตามทฤษฎีของตัวสร้าง
ครั้งแรกที่คุณควรอ่านวิธีการทำงานภาวนาทำงานใน JavaScript ฉันสงสัยว่าคนเดียวก็เพียงพอที่จะตอบคำถามของคุณ แต่นี่เป็นบทสรุปของสิ่งที่เกิดขึ้น:
Array.prototype.slice
สารสกัดจากวิธีจาก's ต้นแบบ แต่เรียกมันโดยตรงจะไม่ทำงานตามที่มันเป็นวิธีการ (ไม่ได้ฟังก์ชั่น)และดังนั้นจึงต้องมีบริบท (วัตถุโทร) มิฉะนั้นก็จะโยนslice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
call()
วิธีช่วยให้คุณระบุบริบทวิธีการของพื้นทำให้ทั้งสองสายเทียบเท่า:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
ยกเว้นวิธีก่อนหน้านี้ต้องการslice
วิธีการที่มีอยู่ในsomeObject
ห่วงโซ่ต้นแบบของ (ในขณะที่มันทำArray
) ในขณะที่หลังช่วยให้บริบท ( someObject
) จะถูกส่งผ่านไปยังวิธีการด้วยตนเอง
นอกจากนี้หลังสั้นสำหรับ:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
ซึ่งเหมือนกับ:
Array.prototype.slice.call(someObject, 1, 2);
// We can apply `slice` from `Array.prototype`:
Array.prototype.slice.call([]); //-> []
// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true
// … we can just invoke it directly:
[].slice(); //-> []
// `arguments` has no `slice` method
'slice' in arguments; //-> false
// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]
// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]
Array.prototype.slice.call (อาร์กิวเมนต์) เป็นวิธีที่ล้าสมัยในการแปลงอาร์กิวเมนต์เป็นอาร์เรย์
ใน ECMAScript 2015 คุณสามารถใช้ Array.from หรือตัวดำเนินการสเปรด:
let args = Array.from(arguments);
let args = [...arguments];
มันเป็นเพราะเป็นบันทึก MDN
วัตถุอาร์กิวเมนต์ไม่ใช่อาร์เรย์ มันคล้ายกับอาร์เรย์ แต่ไม่มีคุณสมบัติอาร์เรย์ใด ๆ ยกเว้นความยาว ตัวอย่างเช่นไม่มีวิธีการแบบป๊อป อย่างไรก็ตามมันสามารถแปลงเป็นอาร์เรย์จริงได้:
ที่นี่เรากำลังเรียกslice
ใช้วัตถุดั้งเดิมArray
ไม่ใช่การใช้งานและนั่นเป็นเหตุผลว่าทำไม.prototype
var args = Array.prototype.slice.call(arguments);
อย่าลืมว่าพื้นฐานระดับต่ำของพฤติกรรมนี้คือการหล่อแบบที่รวมอยู่ใน JS-engine ทั้งหมด
Slice ใช้เวลาวัตถุ (ขอบคุณคุณสมบัติ arguments.length ที่มีอยู่) และส่งคืนวัตถุแถวลำดับหลังจากทำการดำเนินการทั้งหมดในนั้น
Logics เดียวกันคุณสามารถทดสอบว่าคุณพยายามที่จะใช้ String-method ด้วยค่า INT หรือไม่:
String.prototype.bold.call(11); // returns "<b>11</b>"
และนั่นคือคำอธิบายข้างต้น
จะใช้slice
วิธีการที่มีอาร์เรย์และเรียกมันว่ามันthis
เป็นarguments
วัตถุ ซึ่งหมายความว่ามันเรียกว่าราวกับว่าคุณได้arguments.slice()
สมมติarguments
มีวิธีการดังกล่าว
การสร้างชิ้นโดยไม่มีข้อโต้แย้งใด ๆ ก็จะนำองค์ประกอบทั้งหมด - ดังนั้นมันเพียงแค่คัดลอกองค์ประกอบจากarguments
ไปยังอาร์เรย์
สมมติว่าคุณมี: function.apply(thisArg, argArray )
วิธีการใช้จะเรียกใช้ฟังก์ชั่นผ่านในวัตถุที่จะถูกผูกไว้กับสิ่งนี้และอาร์เรย์ของตัวเลือกการขัดแย้ง
วิธีการแบ่ง () เลือกส่วนหนึ่งของอาร์เรย์และส่งกลับอาร์เรย์ใหม่
ดังนั้นเมื่อคุณเรียกArray.prototype.slice.apply(arguments, [0])
ใช้วิธีการแบ่งอาร์เรย์จะถูกเรียกใช้ (ผูก) กับอาร์กิวเมนต์
อาจจะช้าไปหน่อย แต่คำตอบของระเบียบนี้คือการโทร () ถูกใช้ใน JS เพื่อรับมรดก หากเราเปรียบเทียบสิ่งนี้กับ Python หรือ PHP ตัวอย่างเช่นการโทรจะถูกใช้ตามลำดับเป็น super () ในนั้น () หรือ parent :: _ construct ()
นี่คือตัวอย่างของการใช้งานที่ชี้แจงทั้งหมด:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
การอ้างอิง: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance
เมื่อ. slice () ถูกเรียกตามปกตินี่คืออาร์เรย์และจากนั้นมันจะวนซ้ำกว่าอาร์เรย์นั้นและทำงานของมัน
//ARGUMENTS
function func(){
console.log(arguments);//[1, 2, 3, 4]
//var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
var arrArguments = [].slice.call(arguments);//cp array with explicity THIS
arrArguments.push('new');
console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]
ฉันแค่เขียนสิ่งนี้เพื่อเตือนตัวเอง ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
หรือเพียงแค่ใช้ฟังก์ชั่นที่มีประโยชน์$ Aเพื่อเปลี่ยนสิ่งต่าง ๆ ให้เป็นอาเรย์
function hasArrayNature(a) {
return !!a && (typeof a == "object" || typeof a == "function") && "length" in a && !("setInterval" in a) && (Object.prototype.toString.call(a) === "[object Array]" || "callee" in a || "item" in a);
}
function $A(b) {
if (!hasArrayNature(b)) return [ b ];
if (b.item) {
var a = b.length, c = new Array(a);
while (a--) c[a] = b[a];
return c;
}
return Array.prototype.slice.call(b);
}
ตัวอย่างการใช้ ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}