2011-12-05 30 views
7

Hãy nói rằng tôi bắt đầu lên một var cho một Object trong mã của tôilo ngại Javascript của sử dụng 'var' trên một biến đã tồn tại

var base = {x:Infinity, y:Infinity};

và sau đó trong phạm vi cùng tôi làm

var base = {x:0, y:0}

Tôi nhận được rằng tôi có thể sử dụng lại biến hiện tại, nhưng tôi đang cố gắng lặp lại trên một điểm.

  1. Điều này có gây ra bất kỳ sự cố nào cho phạm vi hiện tại liên quan đến bộ nhớ không?
  2. Sẽ có bất kỳ sự cố nào nếu chúng nằm trong các phạm vi khác nhau không?
  3. Quy tắc chung có bao giờ sử dụng var trên biến đã tồn tại không?
  4. Nếu tôi làm điều này vài nghìn lần, tôi có gặp phải bất kỳ vấn đề "sôi nổi nào" không?
+0

# 3 - vâng, nhưng chủ yếu là bởi vì nó dễ dàng hơn để duy trì mã như vậy. – c69

+0

vui lòng đăng thêm một chút mã ví dụ để cho biết bạn sẽ sử dụng mã này như thế nào. Đó là một chút mơ hồ cho dù hoisting biến sẽ là một vấn đề hoặc cho dù mỗi biến là trong một đóng cửa riêng biệt. – zzzzBov

+0

Sử dụng var nhiều lần cho cùng một biến có thể hữu ích khi gỡ lỗi. –

Trả lời

7
  1. Nó giải phóng giữ nó trên giá trị cũ, vì vậy nó có thể có khả năng thu gom rác thải. Tôi nói có khả năng, bởi vì các đối tượng có thể được tham chiếu bởi các biến khác nhau.

  2. Nếu chúng ở các phạm vi khác nhau, bên trong base sẽ đổ bóng bên ngoài (giả sử bạn đang nói về phạm vi lồng nhau), vì vậy giá trị cũ sẽ không bị ghi đè. Bóng tối thường tránh được tốt nhất.

  3. Nói chung, trong phạm vi tương tự, có nhưng đó là nhiều khía cạnh về kiểu mã hóa hơn. Nó sẽ không tạo ra sự khác biệt hiệu quả trong việc thực thi vì chỉ có một khai báo bất kể số lần bạn khai báo cùng một số var trong cùng một phạm vi.

  4. Tùy thuộc. Bạn đang nói về ghi đè trong một vòng lặp? Nếu bạn không còn cần giá trị hiện tại, nó không phải là một vấn đề.


Để được rõ ràng, khi bạn làm điều này:

var base = {x:Infinity, y:Infinity}; 

var base = {x:0, y:0} 

gì thực sự xảy ra này là:

var base; // declaration is hoisted 

base = {x:Infinity, y:Infinity}; // new object is referenced by base 

base = {x:0, y:0} // previous object is released, and new object is referenced 

Lưu ý rằng khi tôi nói về phạm vi và var, tôi đang nói cụ thể về phạm vi chức năng. Trong triển khai JavaScript/ECMAScript chuẩn, không có phạm vi chặn, vì vậy không có ý nghĩa đặc biệt khi sử dụng var trong câu lệnh for chẳng hạn.

Như đã đề cập bởi @Charles Bailey, Mozilla có let, cho phép phạm vi trong các khối, nhưng sẽ yêu cầu từ khóa cụ thể đó. Câu lệnh var không nhận ra khối liên quan đến phạm vi biến.

+0

2 chỉ đúng nếu phạm vi bên trong nằm trong một hàm và phạm vi bên ngoài không phải là. 'let' cho phép phạm vi lồng nhau đầy đủ; 'var' thì không. –

+0

@CharlesBailey: Chắc chắn rồi. Tôi sẽ đưa ra một ví dụ sau một phút. [Ví dụ] (http://jsfiddle.net/pWncd/) – RightSaidFred

+0

chỉ để làm rõ điểm 1, bằng cách sử dụng 'var' không làm điều này, gán nó cái gì khác không. Tức là, nếu cơ sở = "một cái gì đó" và bạn viết 'cơ sở = {foo: 'bar'}' cái gì đó "trong bộ nhớ sẽ được cho thu gom rác thải. –

1

Hoàn toàn không có vấn đề gì khi thực hiện điều đó.Afterall, variables được khai báo trong một hàm (-context) chỉ là một phần của cái gọi là Activation Object (phiên bản ES 3). Nó có một chút khác biệt trong ES5, nhưng đối với phần này thì về cơ bản là giống nhau.

Bạn chỉ ghi đè một thuộc tính, trong một đối tượng (không phải là đối tượng Javascript, nhưng từ cơ chế js bên dưới).

Vì vậy, một lần nữa, đó không phải là một vấn đề gì cả (ngay cả khi nó không bình thường có vẻ khó hiểu).

Nếu bạn khai báo biến trong một "phạm vi" khác (về cơ bản có nghĩa là, một hàm khác ở đây), thì cũng không có vấn đề gì. Mỗi ngữ cảnh (thực thi) hoàn toàn tự nó và không thể can thiệp vào bối cảnh khác, trừ khi chúng ta nói về các bao đóng và các công cụ. Nhưng ngay cả khi đó, nếu bạn có nhiều hàm và ngữ cảnh cha mẹ, tất cả đều có cùng biến tên, quy trình tra cứu (độ phân giải tên) luôn bắt đầu trong phạm vi cục bộ của bạn (đối tượng Kích hoạt từ ngữ cảnh hiện tại) và sau đó, nó đi vào "chuỗi phạm vi".

Tôi đoán điều đó cũng nên trả lời 3.) và 4.). Bạn "có thể" tái biến một biến, nhưng nó không có ý nghĩa. Vì vậy, tôi chỉ khuyên bạn không nên làm điều đó nữa.

0
  1. Từ khóa var cung cấp phạm vi cho biến. Phạm vi duy nhất có sẵn cho JavaScript tại thời điểm này là phạm vi chức năng. Nếu biến đã được scoped để chức năng này sau đó thiết lập với các từ khóa var một lần nữa không có gì.

  2. JavaScript là ngôn ngữ lambda, có nghĩa là các biến được khai báo ở phạm vi cao hơn có sẵn cho các hàm bên trong phạm vi cao hơn đó. Việc cung cấp một biến từ phạm vi cao hơn với từ khóa var trong phạm vi hàm thấp hơn có thể có hại, bởi vì bây giờ bạn đã tạo ra một biến cục bộ có thể được dự định là đóng. Hãy xem xét hai ví dụ sau đây:

    var a = function() { 
        var b = 3, 
         c = function() { 
          var d = 5; 
          b = 5; 
          return d + b; // this is 10 
         }; 
        return c() + b; // this is 10 + 5, or 15 
    }; 
    var a = function() { 
        var b = 3, 
         c = function() { 
          var b = 5, 
           d = 5; 
          return d + b; // this is 10 
         }; 
        return c() + b; // this is 10 + 3, or 13 
    }; 
    

Tôi nói vô tình làm thay đổi phạm vi biến là có hại, bởi vì nó sẽ nhầm lẫn giữa cách mã của bạn hoạt động từ cách bạn nghĩ rằng nó sẽ làm việc.

0

Nguyên tắc chung là một var khai mỗi chức năng, và rằng var khai thuộc ở phía trên cùng của hàm:

function foo() { 
    var bar; 
} 

Lý do để làm điều đó là để tránh nhầm lẫn có thể được gây ra bởi treo biến.

Một ví dụ về nơi này vấn đề là với bối cảnh đóng cửa cho callbacks:

//this looks like it will count up, but it wont 
function foo() { 
    var i; 
    for (i = 0; i < 10; i++) { 
    var bar = i; 
    setTimeout(function() { 
     console.log(bar); 
    }, 1000 * i); 
    } 
} 

//this is actually what's happening behind the scenes 
//hopefully you can see why it wont work 
function foo() { 
    var i, bar; 
    for (i = 0; i < 10; i++) { 
    bar = i; //bar is in the same scope as i 
    setTimeout(function() { 
     //when this is called `i` and `bar` will both have a value of 9 
     console.log(bar); 
    }, 1000 * i); 
    } 
} 

Nếu bạn đã có một phụ chức năng, bạn có thể khai báo một biến mới cùng tên, mà sẽ vẫn cho phạm vi mà phụ chức năng:

function foo() { 
    var bar; 
    function baz() { 
    bar = 2; 
    } 
    bar = 1; 
    baz(); 
    console.log(bar); //output will be 2 because baz operated in the outer scope 
} 


function foo() { 
    var bar; 
    function baz() { 
    var bar; 
    bar = 2; 
    } 
    bar = 1; 
    baz(); 
    console.log(bar); //output will stay 1 because baz operated in its own scope 
} 

Nếu mã ví dụ của bạn là dọc theo dòng:

function foo() { 
    var base = {x:Infinity, y:Infinity}; 
    ...some code... 
    var base = {x:0, y:0}; 
} 

Nó sẽ thực sự thực hiện như sau:

function foo() { 
    var base; 
    base = {x:Infinity, y:Infinity}; 
    ...some code... 
    base = {x:0, y:0}; 
} 
Các vấn đề liên quan