2013-02-13 42 views
5

Gần đây tôi đã nhìn vào mã của firebugs console.log bằng cách gọi console.log.toString() và nhận điều này:Function.apply vs Function.prototype.apply

function() { return Function.apply.call(x.log, x, arguments); } 

Chừng nào tôi hiểu điều này gây ra Function.apply được gọi với this của nó đề cập đến x.log và các đối số là xarguments. Vì các chức năng của chính cuộc gọi Function.apply này sẽ dẫn đến x.log được gọi với số this tham chiếu đến xarguments làm đối số của nó.

Điều gì dẫn tôi đến câu hỏi của mình: Có lý do nào để gọi Function.apply theo cách này thay vì chỉ sử dụng Function.prototype.apply? Hay nói cách khác, có sự khác biệt nào giữa các bên trên và return x.log.apply(x, arguments) không?

Edit: Vì nó là mã nguồn mở Tôi đã xem nhanh tại sourcecode firebug và tìm thấy nơi này được tạo ra (consoleInjector.js, dòng 73):

// Construct a script string that defines a function. This function returns 
// an object that wraps every 'console' method. This function will be evaluated 
// in a window content sandbox and return a wrapper for the 'console' object. 
// Note that this wrapper appends an additional frame that shouldn't be displayed 
// to the user. 
var expr = "(function(x) { return {\n"; 
for (var p in console) 
{ 
    var func = console[p]; 
    if (typeof(func) == "function") 
    { 
     expr += p + ": function() { return Function.apply.call(x." + p + 
      ", x, arguments); },\n"; 
    } 
} 
expr += "};})"; 

// Evaluate the function in the window sandbox/scope and execute. The return value 
// is a wrapper for the 'console' object. 
var sandbox = Cu.Sandbox(win); 
var getConsoleWrapper = Cu.evalInSandbox(expr, sandbox); 
win.wrappedJSObject.console = getConsoleWrapper(console); 

Tôi gần như chắc chắn bây giờ mà điều này có liên quan gì đó với Function để ở trong một phạm vi khác, đó là những gì tôi đã nói trong nhận xét đầu tiên của tôi về câu trả lời của câu trả lời của tôi, nhưng tôi vẫn chưa hiểu hết. Tôi có thể làm một chút nghiên cứu thêm về điều đó.

+0

Tôi tò mò là tại sao mã không chỉ sử dụng kết quả của 'Cu.evalInSandbox (" Function ", sandbox)' trong cách tiếp cận đóng cửa tiêu chuẩn (vì các đối tượng hàm dường như được trả về), nhưng dường như ở đó là một lý do .. thực sự, điều đó không tạo ra nhiều từ một trong hai, vì 'Hàm' nên * không * được đóng lại; trừ khi có nhiều ma thuật trong 'evalInSandbox' .. –

Trả lời

4

Hãy xem xét điều này:

Function.hasOwnProperty("apply")    // false 
Function.apply == Function.prototype.apply // true 
Function.__proto__ == Function.prototype  // true in FF which exposes proto 

Vì vậy Function.apply làm việc vì [[Prototype]] Chức năng là Function.prototype. Trong trường hợp này cả hai phải làm việc như mong muốn.

Tuy nhiên, hãy xem xét rằng bình thường [GetProperty] quy tắc vẫn áp dụng:

var f = function() {}; 
f.apply = "nubbits"; 
f.apply(/* err */); 

Cấp, tôi muốn xem xét nó "mã đáng ngờ" để thay đổi hành vi của apply (và đặc biệt là trong một cách không tương thích), nhưng nó có thể rằng hai hình thức khác nhau .. Cá nhân, tôi làm không chứa các tình huống giả định như vậy và tôi sử dụng f.apply trong mã của mình.

+0

Tôi đã tự hỏi điều này - thì tại sao nó sẽ" tốt hơn "để sử dụng' Function.prototype.apply' trên 'myFunc.apply' (câu hỏi khác của OP)? – Ian

+0

@Ian Có lẽ một người thích "hình thức rõ ràng". Tôi không thể nghĩ ra một lý do phân biệt mà tôi đã gặp phải trong mã của tôi - tôi, tôi thích 'fn.apply' hơn. (Và nếu ai đó thay đổi những gì nó làm, thì đó là trên chúng ..) –

+0

Vì vậy, điều này sẽ chỉ được thực hiện để ngăn chặn một trong những thay đổi hành vi của 'console.log.apply'? Khó có thể nghĩ đây là lý do duy nhất ... Tôi cũng nghĩ rằng điều này có thể được thực hiện bởi vì 'Hàm' (cái mà' áp dụng' được gọi) nằm trong phạm vi khác, mà rất có thể là vấn đề ở đây: http://stackoverflow.com/questions/14715140/why-does-prototyping-function-not-affect-console-log – YingYang

Các vấn đề liên quan