Tôi biết nó được sử dụng để biến các đối số thành một mảng thực sự, nhưng tôi không hiểu điều gì xảy ra khi sử dụng Array.prototype.slice.call(arguments)
Tôi biết nó được sử dụng để biến các đối số thành một mảng thực sự, nhưng tôi không hiểu điều gì xảy ra khi sử dụng Array.prototype.slice.call(arguments)
Câu trả lời:
Điều xảy ra dưới mui xe là khi .slice()
được gọi bình thường, this
là một Mảng, và sau đó nó chỉ lặp lại trên Mảng đó và thực hiện công việc của nó.
Làm thế nào là this
trong .slice()
hàm một mảng? Bởi vì khi bạn làm:
object.method();
... object
tự động trở thành giá trị this
trong method()
. Vì vậy:
[1,2,3].slice()
... các [1,2,3]
mảng được thiết lập như giá trị của this
trong .slice()
.
Nhưng nếu bạn có thể thay thế một cái gì đó khác như this
giá trị thì sao? Miễn là bất cứ thứ gì bạn thay thế đều có .length
thuộc tính số và một loạt các thuộc tính là chỉ số số, nó sẽ hoạt động. Loại đối tượng này thường được gọi là một đối tượng giống như mảng .
Các phương thức .call()
và .apply()
cho phép bạn đặt thủ công giá trị của this
một hàm. Vì vậy, nếu chúng ta thiết lập giá trị của this
trong .slice()
một mảng giống như đối tượng , .slice()
chỉ sẽ giả định nó làm việc với một mảng, và sẽ làm điều này.
Lấy đối tượng đơn giản này làm ví dụ.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Đây rõ ràng không phải là một Array, nhưng nếu bạn có thể đặt nó làm this
giá trị của .slice()
nó, thì nó sẽ chỉ hoạt động, bởi vì nó trông giống như một Array .slice()
để hoạt động chính xác.
var sliced = Array.prototype.slice.call( my_object, 3 );
Ví dụ: http://jsfiddle.net/wSvkv/
Như bạn có thể thấy trong bảng điều khiển, kết quả là những gì chúng ta mong đợi:
['three','four'];
Vì vậy, đây là những gì xảy ra khi bạn đặt một arguments
đối tượng là this
giá trị của .slice()
. Bởi vì arguments
có một thuộc .length
tính và một loạt các chỉ số số, .slice()
chỉ cần thực hiện công việc của nó như thể nó đang làm việc trên một mảng thực.
Array.prototype.slice
mô tả phương pháp.
for-in
tuyên bố không đảm bảo trật tự. Thuật toán được sử dụng bằng cách .slice()
định nghĩa một thứ tự số bắt đầu bằng 0
và kết thúc (không bao gồm) với .length
đối tượng đã cho (hoặc Mảng hoặc bất cứ thứ gì). Vì vậy, thứ tự được đảm bảo là nhất quán trong tất cả các triển khai.
var obj = {2:"two", 0:"zero", 1: "one"}
. Nếu chúng ta sử dụng for-in
để liệt kê đối tượng, không có gì đảm bảo trật tự. Nhưng nếu chúng ta sử dụng for
, chúng ta có thể tự thực thi lệnh : for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Bây giờ chúng ta biết rằng các thuộc tính của đối tượng sẽ đạt được theo thứ tự số tăng dần mà chúng ta đã xác định bởi for
vòng lặp của chúng tôi . Đó là những gì .slice()
. Nó không quan tâm nếu nó có một mảng thực tế. Nó chỉ bắt đầu tại 0
và truy cập các thuộc tính trong một vòng lặp tăng dần.
Đối arguments
tượng không thực sự là một thể hiện của Mảng và không có bất kỳ phương thức Mảng nào. Vì vậy, arguments.slice(...)
sẽ không hoạt động vì đối tượng đối số không có phương thức lát.
Mảng có phương thức này và vì arguments
đối tượng rất giống với một mảng, hai mảng tương thích. Điều này có nghĩa là chúng ta có thể sử dụng các phương thức mảng với đối tượng đối số. Và vì các phương thức mảng được xây dựng với các mảng trong tâm trí, chúng sẽ trả về các mảng thay vì các đối tượng đối số khác.
Vậy tại sao nên sử dụng Array.prototype
? Các Array
là đối tượng mà chúng tôi tạo ra các mảng mới từ ( new Array()
), và những mảng mới được thông qua phương pháp và tài sản, như lát. Các phương thức này được lưu trữ trong [Class].prototype
đối tượng. Vì vậy, vì lợi ích hiệu quả, thay vì truy cập phương thức lát bằng (new Array()).slice.call()
hoặc [].slice.call()
, chúng ta chỉ cần lấy nó trực tiếp từ nguyên mẫu. Điều này là do đó chúng ta không phải khởi tạo một mảng mới.
Nhưng tại sao chúng ta phải làm điều này ngay từ đầu? Như bạn đã nói, nó chuyển đổi một đối tượng đối số thành một đối tượng Array. Lý do tại sao chúng tôi sử dụng lát, tuy nhiên, là một "hack" hơn bất cứ điều gì. Phương thức lát sẽ lấy một, bạn đoán nó, lát một mảng và trả lại lát đó dưới dạng một mảng mới. Việc không truyền đối số cho nó (ngoài đối tượng đối số làm bối cảnh của nó) làm cho phương thức lát cắt lấy một đoạn hoàn chỉnh của "mảng" đã truyền (trong trường hợp này là đối tượng đối số) và trả về nó như một mảng mới.
Thông thường, gọi
var b = a.slice();
sẽ sao chép mảng a
vào b
. Tuy nhiên, chúng tôi không thể làm
var a = arguments.slice();
bởi vì arguments
không phải là một mảng thực sự và không có slice
phương thức. Array.prototype.slice
là slice
hàm cho mảng và call
chạy hàm với this
set arguments
.
prototype
? không phải slice
là một Array
phương pháp bản địa ?
Array
là một hàm tạo, và "lớp" tương ứng là Array.prototype
. Bạn cũng có thể sử dụng[].slice
slice
là một phương thức của mỗi Array
thể hiện, nhưng không phải là Array
hàm tạo. Bạn sử dụng prototype
để truy cập các phương thức của các trường hợp lý thuyết của nhà xây dựng.
Trước tiên, bạn nên đọc cách gọi chức năng hoạt động trong JavaScript . Tôi nghi ngờ rằng một mình là đủ để trả lời câu hỏi của bạn. Nhưng đây là một bản tóm tắt về những gì đang xảy ra:
Array.prototype.slice
chiết xuất các phương pháp từ của nguyên mẫu . Nhưng gọi nó trực tiếp sẽ không hoạt động, vì nó là một phương thức (không phải là một hàm) và do đó đòi hỏi một bối cảnh (một đối tượng gọi ), nếu không nó sẽ ném .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
Các call()
phương pháp cho phép bạn xác định bối cảnh của một phương pháp, về cơ bản làm cho hai cuộc gọi này tương đương với:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
Ngoại trừ cái trước đòi hỏi slice
phương thức tồn tại trong someObject
chuỗi nguyên mẫu (như nó làm Array
), trong khi cái sau cho phép bối cảnh ( someObject
) được truyền thủ công cho phương thức.
Ngoài ra, sau này là viết tắt của:
var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);
Điều này giống như:
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 (đối số) là cách thức cũ để chuyển đổi một đối số thành một mảng.
Trong ECMAScript 2015, bạn có thể sử dụng Array.from hoặc toán tử trải rộng:
let args = Array.from(arguments);
let args = [...arguments];
Bởi vì, như MDN lưu ý
Đối tượng đối số không phải là một mảng. Nó tương tự như một mảng, nhưng không có bất kỳ thuộc tính mảng nào ngoại trừ chiều dài. Ví dụ, nó không có phương thức pop. Tuy nhiên, nó có thể được chuyển đổi thành một mảng thực sự:
Ở đây chúng ta đang kêu gọi slice
đối tượng bản địa Array
chứ không phải thực hiện nó và đó là lý do tại sao thêm.prototype
var args = Array.prototype.slice.call(arguments);
Đừng quên rằng, một điều cơ bản ở mức độ thấp của hành vi này là kiểu truyền được tích hợp hoàn toàn trong công cụ JS.
Slice chỉ lấy đối tượng (nhờ thuộc tính argument.length hiện có) và trả về đối tượng mảng được truyền sau khi thực hiện tất cả các hoạt động trên đó.
Các logic tương tự bạn có thể kiểm tra nếu bạn cố xử lý phương thức String bằng giá trị INT:
String.prototype.bold.call(11); // returns "<b>11</b>"
Và điều đó giải thích tuyên bố trên.
Nó sử dụng các slice
phương pháp mảng có và gọi nó với nó this
là arguments
đối tượng. Điều này có nghĩa là nó gọi nó như thể bạn đã arguments.slice()
giả sử arguments
có một phương pháp như vậy.
Tạo một lát mà không có bất kỳ đối số nào sẽ chỉ đơn giản là lấy tất cả các phần tử - vì vậy nó chỉ cần sao chép các phần tử từ arguments
một mảng.
Giả sử bạn có: function.apply(thisArg, argArray )
Phương thức áp dụng gọi một hàm, truyền vào đối tượng sẽ bị ràng buộc với điều này và một mảng các đối số tùy chọn.
Phương thức lát () chọn một phần của mảng và trả về mảng mới.
Vì vậy, khi bạn gọi Array.prototype.slice.apply(arguments, [0])
phương thức mảng được gọi (liên kết) trên các đối số.
Có thể hơi muộn, nhưng câu trả lời cho tất cả mớ hỗn độn này là lệnh gọi () được sử dụng trong JS để kế thừa. Ví dụ, nếu chúng ta so sánh nó với Python hoặc PHP, cuộc gọi được sử dụng tương ứng là super (). init () hoặc cha mẹ :: _ xây dựng ().
Đây là một ví dụ về việc sử dụng nó làm rõ tất cả:
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
Tham khảo: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inherribution
khi .slice () được gọi bình thường, đây là một mảng và sau đó nó chỉ lặp lại trên mảng đó và thực hiện công việc của nó.
//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"]
Tôi chỉ viết điều này để nhắc nhở bản thân ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
Hoặc chỉ sử dụng hàm tiện dụng $ A này để biến hầu hết mọi thứ thành một mảng.
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);
}
sử dụng ví dụ ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}