2010-05-10 31 views
16

Hãy nói rằng chúng tôi có mã này (quên về nguyên mẫu cho một thời điểm):Are đóng cửa trong javascript biên dịch lại

function A(){ 
    var foo = 1; 
    this.method = function(){ 
    return foo; 
    } 
} 
var a = new A(); 

là chức năng bên trong biên dịch lại mỗi khi hàm A được chạy? Hoặc là tốt hơn (và tại sao) để làm điều đó như thế này:

function method = function(){ return this.foo; } 
function A(){ 
    this.foo = 1; 
    this.method = method; 
} 
var a = new A(); 

Hoặc là các công cụ javascript đủ thông minh để không tạo chức năng 'phương pháp' mới mỗi lần? Cụ thể là v8 và node.js. của Google

Ngoài ra, mọi khuyến nghị chung về thời điểm sử dụng kỹ thuật nào được hoan nghênh. Trong ví dụ cụ thể của tôi, nó thực sự phù hợp với tôi để sử dụng ví dụ đầu tiên, nhưng tôi biết rằng hàm bên ngoài sẽ được khởi tạo nhiều lần.

+1

Câu hỏi thú vị. Tôi muốn sẵn sàng đặt cược rằng các thông dịch viên JavaScript thông minh hơn thế. –

+0

Thành thật mà nói, nếu bạn lo lắng về hiệu suất, đây không phải là nút cổ chai của bạn. Tôi không lo lắng về điều đó. –

+0

Bạn muốn thực hiện một getter trên một biến riêng mà không được nhân rộng với mọi lời gọi hàm tạo? – Alsciende

Trả lời

7

Từ những gì tôi hiểu, nó không phải là vấn đề "biên dịch" hàm vì nó có "phạm vi" khác nhau mỗi khi nó được thực hiện.

Phương pháp thứ hai bạn đã sử dụng sẽ luôn có method từ cùng một phạm vi.

Phương pháp đầu tiên đặt method trong phạm vi cuộc gọi hàm A(). Vì vậy, bất kỳ thông tin nào nằm trong phạm vi đó (var foo, thông số chức năng, v.v.) được lưu trữ trong ví dụ phạm vi chức năng đó. Vì vậy, cùng một mã chức năng sẽ được tham chiếu mỗi lần, nhưng nó sẽ nằm trong một phạm vi khác (và do đó là một "đối tượng" khác).

+0

+1, câu trả lời hay nhất và ngắn gọn nhất ở đây (và bạn thực sự đã trả lời câu hỏi!). –

2

Phương pháp này không được biên dịch lại.

Trình thông dịch Javascript sẽ tạo đối tượng đóng mới chứa các phương thức bên trong và biến cục bộ mỗi khi bạn gọi các phương thức bên ngoài.

Việc triển khai chính xác tùy thuộc vào công cụ Javascript.

+1

Bất kỳ suy nghĩ nào về Google v8? – disc0dancer

+0

Tôi không biết. – SLaks

0

Tôi đoán nó chỉ được biên dịch một lần ... vì từ khóa "này" đề cập đến ngữ cảnh thực hiện ... do đó trình biên dịch không cần biết nhiều về hàm để diễn giải nó.

Hơn nữa, khi bạn khai báo một biến ở dưới cùng của một hàm, nó vẫn còn truy cập ở đầu trang:

function test() 
{ 
    alert(hello); 
    // ... 
    var hello = 2; 
} 

Đây là điều tương tự với chức năng. Tôi sẽ tin với 2 điều đó trong tâm trí, rằng nó không được tái biên dịch mỗi khi A được gọi.

Mike

+0

Thực ra - điều này sẽ cảnh báo 'không xác định'. Tuyên bố biến được nâng lên đỉnh, nhưng 'hello' không được đặt thành' 2' cho đến sau cảnh báo. –

3

Có, bạn đang tạo đối tượng hàm mới tại mỗi lần khởi tạo đối tượng A. Bạn có thể chứng minh điều này như sau:

function A(){ 
    var foo = 1; 
    this.method = function(){ 
    return foo; 
    } 
} 
var a = new A(); 
var b = new A(); 
alert(a.method == b.method); // Returns false; two different Function objects 

Nếu bạn muốn sử dụng lại cùng một đối tượng Function, làm cho phương thức trở thành tài sản của nguyên mẫu, không phải là trường hợp.

function B() { 
    this.foo = 1; 
} 

B.prototype.method = function() { 
    return this.foo; 
} 

var a = new B(); 
var b = new B(); 
alert(a.method == b.method); // Returns true; it's the same Function object 

Edit: Theo như tôi biết, không có lý do để làm một cái gì đó giống như phiên bản đầu tiên ngoại trừ việc tạo ra các biến riêng trong một đối tượng JavaScript. Trong ví dụ ban đầu, foo là riêng tư. Không có gì có thể truy cập trực tiếp từ bên ngoài đối tượng.Thật không may, khi bạn đang instantiating một số lượng lớn các đối tượng sử dụng kỹ thuật này, nó có thể có tác động đến hiệu suất và bộ nhớ.

Trong mã của tôi, tôi sử dụng quy ước đặt tên để phân biệt giữa thuộc tính "công khai" và "riêng tư". Tôi đặt tên các thuộc tính riêng với dấu gạch dưới là ký tự đầu tiên. Vì vậy, nếu tôi thấy một cái gì đó như myObject._someMethod(), tôi biết điều gì đó sai.


Edit2: Từ http://code.google.com/apis/v8/design.html, tôi sẽ nghĩ rằng V8 biên dịch việc đóng cửa một lần, khi nó tạo ra những lớp ẩn chứa method tài sản.

+0

Điều này rất thú vị. Nó có thể được rằng các nhà điều hành bình đẳng cố ý phân biệt hai phương pháp, nhưng họ đang thực sự giống nhau? Tôi biết rằng tôi có thể sử dụng nguyên mẫu, nhưng tôi muốn bỏ qua điều đó cho trường hợp này. – disc0dancer

+2

@Discodancer: Hai phương thức có cùng mã, nhưng chúng là các đối tượng khác nhau, giống như nếu bạn làm một cái gì đó như 'a = {}; b = {}; cảnh báo (a == b); // false'. – jhurshman

+1

Hiệu suất đạt được khi sử dụng biến cục bộ ("riêng tư") là không đáng kể đối với phiên dịch hiện đại. Tôi không biết về trí nhớ, nhưng tôi cá rằng nó không đủ lớn để tạo nên sự khác biệt lớn. –

0

Hãy tưởng tượng một hàm chỉ là một đối tượng khác, và sau đó khi bạn tạo một đối tượng mới, nó chỉ là bản sao của đối tượng cũ, với một số biến dữ liệu đã thay đổi. Bạn không cần phải phân tích lại nguồn của đối tượng để điều đó xảy ra. Một sự tương tự tốt là các hàm trong C++, các đối tượng hàm trong Lua, và tôi không thực sự biết nhiều ngôn ngữ khác.

0
function A(){ 
    var foo = 1; 
    this.method = function(){ 
    return foo; 
    } 
} 

không thể được biên dịch vào

function method = function(){ return this.foo; } 
function A(){ 
    this.foo = 1; 
    this.method = method; 
} 

vì các chức năng sẽ thay đổi. Ví dụ đầu tiên có biến 'foo' chỉ hiển thị với hàm tạo 'A' và hàm được gọi là 'phương thức' trong khi trong ví dụ thứ hai, mọi thứ có thể truy cập vào cá thể 'A'.

Có thể biên dịch nó thành

function method = function(){ return 1; } 
function A(){ 
    this.method = method; 
} 

Nhưng tôi không nghĩ rằng bất kỳ công cụ javascript ra khỏi đó sẽ đi xa, nhưng nếu bạn có thể xử lý trước tập tin của bạn và sẵn sàng để đưa vào một thêm chút nỗ lực, các google closure compiler có thể đi khá xa nếu nó được sử dụng trong chế độ nâng cao.

+0

Câu hỏi của tôi là liệu ví dụ đầu tiên tạo ra các cá thể mới của hàm mỗi khi tôi chạy A(), không phải liệu nó có thể được biên dịch vào ví dụ khác hay không. – disc0dancer

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