2016-02-21 20 views
43

Kể từ lớp ES6 chỉ là một đường cú pháp qua thừa kế dựa trên nguyên mẫu hiện có JavaScript của[1] nó sẽ (IMO) làm cho tinh thần để nhấc nó định nghĩa:Tại sao các lớp học ES6 không được treo?

var foo = new Foo(1, 2); //this works 

function Foo(x, y) { 
    this.x = x; 
    this.y = y; 
} 

Nhưng sau đây sẽ không hoạt động:

var foo = new Foo(1, 2); //ReferenceError 

class Foo { 
    constructor(x, y) { 
     this.x = x; 
     this.y = y; 
    } 
} 

Tại sao các lớp học ES6 không được treo?

+3

Các lớp ES6 * không * chỉ là cú pháp, mặc dù chúng hầu hết là * đường cú pháp. –

+2

Tời kéo là một nguồn hiểu lầm và nhầm lẫn gần như vô tận. Tất cả các cấu trúc khai báo mới ('let',' const', 'class') được thêm vào trong ES6 đều không được lưu trữ (tốt, chúng là * half-hoisted *). Chặn một trích dẫn từ Eich hoặc tương tự, bạn sẽ không nhận được câu trả lời mà không phải là suy đoán hiệu quả. –

+0

@mmm: MDN được cộng đồng chỉnh sửa và đôi khi sai. Không thường xuyên, không phải là thường xuyên như, nói rằng, trang web khác, nhưng đôi khi. Xem [câu trả lời này] (http://stackoverflow.com/a/31222689/157247) để biết cách chúng được treo và không treo. –

Trả lời

41

Tại sao các lớp học ES6 không được treo?

Trên thực tế họ kéo lên (biến ràng buộc có sẵn trong toàn bộ phạm vi) giống như let and const are - họ chỉ không được khởi tạo.

Nó sẽ làm cho tinh thần để Palăng định nghĩa của nó

số Đó là không bao giờ là một ý tưởng tốt để sử dụng một lớp học trước khi định nghĩa của nó. Hãy xem xét ví dụ

var foo = new Bar(); // this appears to work 
console.log(foo.x) // but doesn't 

function Bar(x) { 
    this.x = x || Bar.defaultX; 
} 
Bar.defaultX = 0; 

và so sánh nó với

var foo = new Bar(); // ReferenceError 
console.log(foo.x); 

class Bar { 
    constructor (x = Bar.defaultX) { 
     this.x = x; 
    } 
} 
Bar.defaultX = 0; 

đó ném một lỗi như bạn mong đợi. Đây là một vấn đề cho các thuộc tính tĩnh, mixin nguyên mẫu, trang trí và mọi thứ. Ngoài ra nó là khá quan trọng cho subclassing, mà đã phá vỡ hoàn toàn trong ES5 khi bạn sử dụng một lớp học với nguyên mẫu không điều chỉnh của nó, nhưng bây giờ ném một lỗi nếu một lớp học eded chưa được khởi tạo.

+0

Để làm rõ trong ví dụ đầu tiên của bạn, vấn đề là 'console.log (foo.x)' sẽ mang lại 'undefined' thay vì' 0' không phải là sẽ có lỗi thời gian chạy. –

3

Trong Javascript tất cả các tờ khai (var, hãy, const, chức năng, chức năng *, lớp) đều được kéo lên nhưng nó cần được khai báo trong cùng phạm vi.

Như bạn nói "lớp ES6 chỉ là một đường cú pháp trên JavaScript của thừa kế dựa trên nguyên mẫu hiện"

Vì vậy, Chúng ta hãy hiểu nó là gì?

Ở đây bạn đã khai báo một lớp thực tế là "hàm đặc biệt". Giả sử rằng hàm Foo() và lớp Foo của bạn đều nằm trong phạm vi toàn cục.

class Foo { 
    constructor(x, y) { 
     this.x = x; 
     this.y = y; 
    } 
} 

Sau đây là mã được biên dịch của lớp học của bạn Foo.

var Foo = (function() { 
    function Foo(x, y) { 
     this.x = x; 
     this.y = y; 
    } 
    return Foo; 
}()); 

Nội bộ lớp học của bạn được chuyển thành chức năng có cùng tên bên trong hàm wrapper (iife) và hàm bao hàm đó trả về hàm của bạn.

Vì phạm vi (lớp) của hàm được thay đổi. và bạn đang cố gắng tạo ra đối tượng của hàm trong phạm vi toàn cục mà trong thực tế không tồn tại.

bạn nhận được hàm trong biến Foo khi biên dịch xuất hiện. vì vậy sau này bạn có chức năng trong var bạn có thể tạo đối tượng đó.

+0

Trong khi nó có một hiệu ứng tương tự, đây không phải là những gì sẽ xảy ra. Không có IIFE được tạo ra để đánh giá lớp học. https://www.ecma-international.org/ecma-262/8.0/#sec-runtime-semantics-classdefinitionevaluation –

+0

nếu tôi không sai cú pháp iife này (hàm() {}()). nếu bạn biên dịch lớp mã này sẽ được tạo ra. Kể từ khi nó được gán cho var nó không được gọi trên toàn cầu. thay vào đó, nó tự gọi và trả về giá trị cho Foo. –

+0

Nếu bạn sử dụng một cái gì đó như babel, vâng. Nhưng môi trường hỗ trợ các lớp học nguyên bản sẽ không làm điều đó. –

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