2012-03-30 28 views
5

xem xét mã:Tại sao Javascript không cho phép một chức năng xác định lại chính nó từ bên trong chính nó?

window.a = function(x){ 
     var r = x*2; 
     window.a =alert; // redefines itself after first call 
     return r; 
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4" 

này không làm việc một trong hai:

window.a = function(x){ 
     alert(x); 
     window.a = function(x){ // redefines itself after first call 
      var r = x*2; 
      return r; 
     } 
    }; 
    a('2 * 2 = '+a(2)); // doesn't work. it should've alerted "2 * 2 = 4" 

Như không phải thực hiện điều này:

window.a = function(x){ alert(x); window.c = window.a; window.a = window.b; window.b = window.c; }; 
    window.b = function(x){ var r = x*2; window.c = window.b; window.b = window.a; window.a = window.c; return r; }; 
    a('2 * 2 = '+a(2)); // doesn't work. 

Và về cơ bản tôi đã thử tất cả những cách có thể và không dường như thực hiện công việc. Ai đó có thể giải thích tại sao?

+1

chỉ vì tò mò, tại sao bạn lại cố gắng làm điều này? – maialithar

+0

Vâng, điều đầu tiên thực sự hiệu quả đối với tôi (Chrome 18) – Yoshi

+0

Hoạt động tốt trong Chrome và IE ... –

Trả lời

8

Bạn xác định lại thành công hàm, chỉ là biểu thức gọi nó đã nắm lấy tham chiếu hàm cũ: Điều đầu tiên xảy ra trong biểu thức cuộc gọi là điều xác định chức năng gọi cần được đánh giá, xem Section 11.2.3 của đặc tả:

11.2.3 Chức năng cuộc gọi

việc sản xuất CallExpression: Arguments MemberExpression được đánh giá một s sau:

  1. Hãy ref là kết quả của việc đánh giá MemberExpression.
  2. Hãy để func là GetValue (ref).
  3. Hãy để argList là kết quả của việc đánh giá Đối số, tạo danh sách giá trị đối số nội bộ (xem 11.2.4).
  4. Nếu loại (func) không phải là đối tượng, hãy ném ngoại lệ TypeError.
  5. Nếu IsCallable (func) là sai, hãy ném ngoại lệ TypeError.
  6. Nếu Kiểu (ref) là tham khảo, sau đó
        a) Nếu IsPropertyReference (ref) là đúng, sau đó
                i. Hãy để thisValue là GetBase (ref).
        b) khác, các cơ sở của ref là một Ghi Môi trường
                i. Hãy để thisValue là kết quả của việc gọi phương thức bê tông ImplicitThisValue của GetBase (ref).
  7. Khác, Loại (ref) không phải là Tham chiếu.
    a) Hãy để thisValue không được xác định.
  8. Return kết quả của cách gọi [[Gọi]] phương pháp nội bộ về func, cung cấp thisValue như giá trị này và cung cấp danh sách argList như các giá trị tham số.

Các bước 1 và 2 xảy ra trước khi hàm được xác định lại.

Giải pháp là tất nhiên để làm cho mọi việc xảy ra theo thứ tự bạn mong đợi (live example | source):

window.a = function(x){ 
    var r = x*2; 
    window.a =alert; // redefines itself after first call 
    return r; 
}; 
var val = a(2); 
a('2 * 2 = '+ val); 

Side lưu ý: Thật thú vị khi your first example công trình trong Chrome (V8) (nó cũng hoạt động trong phiên bản JScript của IE6, nhưng sau đó, JScript có số lô hàng rất nhiều). Nó không hoạt động, và không có trong Firefox (SpiderMonkey), Opera (Carakan), hoặc IE9 (Chakra).

1

JavaScript có quy tắc từ trái sang phải nghiêm ngặt cho thứ tự đánh giá đối số toán tử. Tôi đoán rằng điều này bao gồm toán tử gọi hàm, nghĩa là a đầu tiên được đánh giá trước biểu thức.

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