2015-06-17 16 views
11

... Vì vậy, ES6¹ (mà xảy ra được tiêu chuẩn hóa trong một vài giờ trước) mang thông số mặc định cho các chức năng tương tự như trong PHP, Python vv Tôi có thể làm công cụ như:`This` hoạt động như thế nào trong các tham số mặc định?

function foo (bar = 'dum') { 
    return bar; 
} 

foo(1); // 1 
foo(); // 'dum' 
foo(undefined); // 'dum' 

MDN nói rằng giá trị mặc định cho tham số được đánh giá tại thời gian gọi. Có nghĩa là mỗi khi tôi gọi hàm, biểu thức 'dum' được đánh giá lại (trừ khi triển khai thực hiện một số tối ưu hóa lạ mà chúng tôi không quan tâm).

Câu hỏi của tôi là, cách this chơi trò chơi này?

let x = { 
    foo (bar = this.foo) { 
    return bar; 
    } 
} 

let y = { 
    z: x.foo 
} 

x.foo() === y.z(); // what? 

Các babel transpiler hiện evaluates² nó như false, nhưng tôi không nhận được nó. Nếu họ đang thực sự đánh giá ở thời gian gọi, những gì về vấn đề này:

let x = 'x from global'; 

function bar (thing = x) { 
    return thing; 
} 

function foo() { 
    let x = 'x from foo'; 
    return bar(); 
} 

bar() === foo(); // what? 

Các babel transpiler hiện evaluates³ nó như true, nhưng tôi không nhận được nó. Tại sao bar không lấy số x từ foo khi được gọi bên trong foo?

1 - Có, tôi biết đó là ES2015.
2-Example A
3 - Example B

+0

Có thông báo nào về việc Ban chấp nhận bản dự thảo ES6 cuối cùng không? –

+1

@squint thông số kỹ thuật có tại http://www.ecma-international.org/ecma-262/6.0/index.html :) –

+0

Rất tốt, cảm ơn! .. –

Trả lời

11

Câu hỏi của tôi là, cách thực hiện this? Tôi không hiểu. Chúng có thực sự được đánh giá vào thời gian gọi không?

Có, trình khởi tạo thông số được đánh giá vào thời gian gọi. It's complicated, nhưng các bước cơ bản như sau:

  1. Một new execution context được thành lập trên stack,
    với một new environment trong "phạm vi đóng cửa" của các chức năng gọi
  2. Nếu cần thiết, đó là thisBinding is initialised
  3. Declarations are instantiated:
    1. Ràng buộc có thể thay đổi cho tên thông số được tạo
    2. Nếu ne cessary, một đối tượng arguments được tạo ra một ràng buộc
    3. Các bindings are iteratively initialised khỏi danh sách đối số (bao gồm tất cả destructurings vv)
      Trong quá trình này, initialisers are evaluated
    4. Nếu bất kỳ đóng cửa đã tham gia, một môi trường mới được chèn
    5. Các liên kết có thể thay đổi cho các biến được khai báo trong thân hàm được tạo (nếu chưa được thực hiện bởi tên tham số) và được khởi tạo bằng undefined
    6. Các ràng buộc cho các biến số letconst trong nội dung hàm được tạo
    7. Các bindings cho các chức năng (từ tờ khai chức năng trong cơ thể) được khởi tạo với các chức năng được thuyết minh
  4. Cuối cùng body of the function is evaluated.

initialisers Vì vậy, tham số nào có quyền truy cập vào các thisarguments của cuộc gọi, để trước khởi tạo các thông số khác, và tất cả mọi thứ đó là trong phạm vi từ vựng "trên" của họ. Chúng không bị ảnh hưởng bởi các biến được khai báo trong phần thân hàm (mặc dù chúng bị ảnh hưởng bởi tất cả các tham số khác, ngay cả khi trong vùng chết tạm thời của chúng).

gì về điều này:

function bar (thing = x) {} 
{ 
    let x = 'x from foo'; 
    return bar(); 
} 

Tôi không nhận được nó. Tại sao bar không dùng số x từ foo khi được gọi là bên trong foo?

x là một biến địa phương mà bar không có quyền truy cập vào.Chúng tôi thật may mắn vì họ là not dynamically scoped! Các initialisers tham số không được đánh giá tại trang gọi, nhưng bên trong phạm vi của hàm được gọi. Trong trường hợp này, số nhận dạng x được giải quyết cho biến số toàn cầu x.

+0

Nếu có ai quan tâm, chúng tôi đã thảo luận thêm về vấn đề này trong [chat] (http://chat.stackoverflow.com/rooms/17/conversation/continued-discussion-for-how-does-this-work-in-default- tham số) nếu bạn muốn đọc :) –

0

Khi họ nói "được đánh giá vào thời điểm cuộc gọi", tôi nghĩ rằng họ đang đề cập đến một cuộc gọi-by-tên biểu . Đây là cách babel kết quả đầu ra ví dụ thứ ba của bạn:

'use strict'; 

var x = 'x from global'; 

function bar() { 
    var thing = arguments[0] === undefined ? x : arguments[0]; 

    return thing; 
} 

function foo() { 
    var x = 'x from foo'; 
    return bar(); 
} 

bar() === foo(); // what? 

Kể từ var x được thừa hưởng trong phạm vi từ vựng của bar từ phạm vi toàn cầu, có nghĩa là phạm vi trong đó nó được sử dụng.

Bây giờ, hãy xem xét những điều sau đây:

let i = 0; 

function id() { 
    return i++; 
} 

function bar (thing = id()) { 
    return thing; 
} 

console.info(bar() === bar()); // false 

nào transpiles để

"use strict"; 

var i = 0; 

function id() { 
    return i++; 
} 

function bar() { 
    var thing = arguments[0] === undefined ? id() : arguments[0]; 

    return thing; 
} 

console.info(bar() === bar()); // false 

Thông báo như thế nào đây, id được gọi bên chức năng, chứ không phải được lưu trữ và memoized tại thời điểm chức năng là được xác định, do đó gọi theo tên thay vì gọi theo giá trị.

Vì vậy, hành vi thực sự chính xác trong ví dụ thứ hai của bạn. Không có y.foo và kể từ thisđộng scoped trong Javascript (tức là nó sẽ thay đổi dựa trên người nhận của một hàm gọi nhất định), khi y.z() tìm kiếm this.foo, nó sẽ tìm kiếm nó trong y, vì vậy y.z() sẽ trở lại undefined, trong khi x.foo() sẽ chỉ trả về chính hàm foo.

Nếu bạn làm muốn liên kết với người nhận, bạn có thể ràng buộc foo-x khi bạn gán nó. Sau đó, nó sẽ làm việc như mong đợi.

Xin lỗi nếu bất kỳ điều này không rõ ràng; hãy cho tôi biết trong phần bình luận và tôi rất sẵn lòng làm rõ! :)

+0

_ "và vì đây là phạm vi động trong Javascript" _, đây là câu hỏi của tôi. Sử dụng 'this.something' không nên được thực hiện đặc biệt bởi vì' this.something' không phải là phép thuật, chỉ 'this' là. Tôi sẽ thêm một ví dụ rõ ràng cho câu hỏi để làm rõ điều này, cảm ơn câu trả lời! –

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