2011-12-28 27 views
60

Mọi người có thể giải thích ngữ cảnh để sử dụng các phương thức callapply trong Javascript không?ngữ cảnh để sử dụng cuộc gọi và áp dụng trong Javascript?

Tại sao sử dụng callapply thay vì gọi trực tiếp một chức năng?

+2

[Đọc này] (https://t.co/BVQPwfqqnO) đã giúp tôi hiểu điểm 'thisArg' khi gọi 'apply()' và 'call() 'mà dường như là cốt lõi của câu hỏi của bạn. Bạn cần hiểu nguyên hàm invocation trong Javascript –

Trả lời

20

Chỉ khi bạn sử dụng call hoặc apply bạn có thể sửa đổi ngữ cảnh this bên trong hàm.

Không giống như các ngôn ngữ khác - trong JavaScript this không đề cập đến đối tượng hiện tại - thay vì ngữ cảnh thực thi và có thể được đặt bởi người gọi.

Nếu bạn gọi một chức năng bằng cách sử dụng từ khóa newthis một cách chính xác sẽ giới thiệu đến các đối tượng mới (bên trong hàm constructor) ..

Nhưng trong mọi trường hợp khác - this sẽ đề cập đến đối tượng toàn cầu trừ khi thiết lập một cách rõ ràng thông qua hãy gọi

+0

Nó có thể ám chỉ đến obj người gọi, nếu sử dụng cú pháp 'obj.whatever();'. –

+0

Câu lệnh "Nhưng trong tất cả các trường hợp khác - điều này sẽ ám chỉ đối tượng toàn cục trừ khi được thiết lập rõ ràng thông qua cuộc gọi" cần được sửa thành sau: "Nhưng trong tất cả các trường hợp khác, trừ khi đặt rõ ràng thông qua cuộc gọi, điều này sẽ ám chỉ đối tượng chung sử dụng Ecmascript 3 hoặc Ecmascript 5 (hoặc mới hơn) ở chế độ không nghiêm ngặt.Tuy nhiên, trong Ecmascript 5 (hoặc mới hơn) với chế độ nghiêm ngặt, điều này luôn luôn không xác định nếu không được đặt rõ ràng và JS Engine sẽ ném một ngoại lệ khi bạn truy cập. " Tham khảo: http://stackoverflow.com/questions/9822561/why-is-this-in-an-anonymous-function-undefined-when-using-strict –

68

Bạn sử dụng call hoặc apply khi bạn muốn chuyển giá trị this khác nhau cho hàm. Về bản chất, điều này có nghĩa là bạn muốn thực hiện một hàm như thể nó là một phương thức của một đối tượng cụ thể. Sự khác biệt duy nhất giữa hai là call hy vọng các tham số được phân tách bằng dấu phẩy, trong khi apply mong đợi các tham số trong một mảng.

Một ví dụ từ Mozilla's apply page, nơi nhà xây dựng đang bị xiềng xích:

function Product(name, price) { 
    this.name = name; 
    this.price = price; 

    if (price < 0) 
     throw RangeError('Cannot create product "' + name + '" with a negative price'); 
    return this; 
} 

function Food(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'food'; 
} 
Food.prototype = new Product(); 

function Toy(name, price) { 
    Product.apply(this, arguments); 
    this.category = 'toy'; 
} 
Toy.prototype = new Product(); 

var cheese = new Food('feta', 5); 
var fun = new Toy('robot', 40); 

Product.apply(this, arguments) làm như sau: Các nhà xây dựng Product được áp dụng như một chức năng trong mỗi FoodToy nhà thầu, và mỗi một trong các đối tượng các phiên bản đang được chuyển thành this. Do đó, mỗi FoodToy hiện có các thuộc tính this.namethis.category.

+5

chỉ là một câu hỏi về đoạn mã được cung cấp, tại sao Toy and Food's nguyên mẫu được thay thế bởi một đối tượng sản phẩm? – davids

+0

Nhận xét chỉ để bump @davids câu hỏi: tại sao chúng ta cần phải làm 'Toy.prototype = new Product();'? Tôi đã thử nghiệm điều này và loại bỏ những dòng này dường như không có sự khác biệt trong kết quả cuối cùng. – adrianp

+6

@davids & @adrianp: Cần thiết để làm cho Đồ ăn và Đồ chơi kế thừa từ Sản phẩm. Hãy xem ví dụ này: http://jsfiddle.net/Shawn/xNEYf/ Tôi đã xóa 'Toy.prototype = new Product();' nhưng còn lại 'Food.prototype = new Product();' trong, vì vậy bây giờ thực phẩm thừa hưởng từ Sản phẩm, nhưng Toy thì không. Tôi cũng đã thêm một phương thức vào nguyên mẫu của Product và gọi nó là từ Food and Toy để làm cho việc thừa kế thiếu rõ ràng hơn (chỉ cần mở console và chạy mã, Food có thể gọi phương thức được thừa kế từ Product, nhưng Toy không thể và ném lỗi) . – Shawn

3

Nếu bạn có kinh nghiệm với jQuery, bạn sẽ biết rằng hầu hết các chức năng đều sử dụng đối tượng this. Ví dụ: collection.each(function() { ... }); Bên trong hàm này, "this" đề cập đến đối tượng trình lặp. Đây là một cách sử dụng có thể.

Cá nhân tôi đã sử dụng .apply() để triển khai hàng đợi yêu cầu - tôi đẩy một loạt đối số vào hàng đợi và khi đến lúc thực thi nó, tôi lấy một phần tử và chuyển nó làm đối số cho hàm xử lý sử dụng .apply(), do đó làm cho mã sạch hơn sau đó nếu phải vượt qua một mảng đối số như một đối số đầu tiên. Đó là một ví dụ khác.

Nói chung, xin lưu ý rằng những cách gọi hàm này tồn tại và bạn có thể thấy một ngày nào đó thuận tiện để sử dụng để triển khai chương trình của mình.

6

Bạn sử dụng .call() khi bạn muốn làm cho hàm thực thi với giá trị this khác. Nó đặt giá trị this như được chỉ định, đặt các đối số như được chỉ định và sau đó gọi hàm. Sự khác biệt giữa .call() và chỉ thực thi hàm là giá trị của con trỏ this khi hàm thực thi.Khi bạn thực thi hàm bình thường, javascript sẽ quyết định con trỏ this sẽ là gì (thường là ngữ cảnh chung window trừ khi hàm được gọi là phương thức trên đối tượng). Khi bạn sử dụng .call(), bạn chỉ định chính xác những gì bạn muốn this được đặt thành.

Bạn sử dụng .apply() khi đối số bạn muốn chuyển đến hàm nằm trong một mảng. .apply() cũng có thể khiến chức năng thực thi với giá trị this cụ thể. .apply() thường được sử dụng nhất khi bạn có số đối số không xác định đến từ một số nguồn khác. Nó thường được sử dụng quá vượt qua các đối số từ một cuộc gọi chức năng khác bằng cách sử dụng biến cục bộ đặc biệt arguments, trong đó có một mảng đối số được chuyển đến hàm hiện tại của bạn.

Tôi tìm thấy trang tham chiếu MDN cho .call().apply() hữu ích.

+0

Cảm ơn bạn, bạn giải thích nó rất tốt. Cuối cùng hiểu cách sử dụng đối số đầu tiên. –

0

Tôi không thể nghĩ ra bất kỳ tình huống bình thường nào khi đặt thisArg thành thứ gì đó khác nhau là mục đích sử dụng.

Mục đích của việc áp dụng là chuyển một mảng giá trị cho một hàm muốn các giá trị đó làm đối số.

Nó đã được thay thế trong tất cả việc sử dụng hàng ngày thông thường của nhà điều hành dàn trải.

ví dụ:

// Finding the largest number in an array 
`Math.max.apply(null, arr)` becomes `Math.max(...arr)` 

// Inserting the values of one array at the start of another 
Array.prototype.unshift.apply(arr1, arr2); 
// which becomes 
arr1 = [...arr2, ...arr1] 
0

Nếu bạn có kinh nghiệm với Object Oriented Programming sau đó gọi và áp dụng sẽ có ý nghĩa nếu bạn so sánh nó với thừa kế và ghi đè các thuộc tính hay phương thức/chức năng của lớp cha mẹ từ lớp trẻ. Điều này tương tự với lệnh gọi javascript như sau:

function foo() { 
    this.helloworld = "hello from foo" 
} 
foo.prototype.print = function() { 
    console.log(this.helloworld) 
} 

foo.prototype.main = function() { 
    this.print() 
} 


function bar() { 
    this.helloworld = 'hello from bar' 
} 
// declaring print function to override the previous print 
bar.prototype.print = function() { 
    console.log(this.helloworld) 
} 

var iamfoo = new foo() 

iamfoo.main() // prints: hello from foo 

iamfoo.main.call(new bar()) // override print and prints: hello from bar 
Các vấn đề liên quan