2010-09-08 41 views
7

Nếu chúng tôi cótên đối tượng giống với tên hàm?

var randomname = {}; 
randomname.attribute = 'something'; 

function randomname(){ 
    alert(randomname.attribute); 
} 
randomname(); 

javascript sẽ phát hiện lỗi nào?


Cập nhật
Vì vậy, Chúng tôi biết rằng chúng tôi không thể có một đối tượng có tên giống như một hàm.

Tại sao điều này?

javascript có thể không biết được bạn đang làm gì sau khi bạn gọi nó?

+0

điều này thực sự làm tôi ngạc nhiên và điều đó thật tuyệt vời khi biết. nhưng nếu bạn muốn sử dụng cùng một tên có lẽ bạn nên sử dụng var name = function() {} thay vì để tránh ý thức suy nghĩ về hành vi tinh vi này nữa. –

Trả lời

17

Nó sẽ cung cấp cho bạn một ngoại lệ TypeError - vì cố gắng gọi một đối tượng-, hành vi được quan sát trong bảng điều khiển của Firebug là không đúng ...

FunctionDeclaration 's là hoisted lên đỉnh phạm vi bao quanh họ, mã của bạn là thực sự thực hiện theo thứ tự này:

// FunctionDeclaration is hoisted 
function randomname(){ 
    alert(randomname.attribute); 
} 

// the var has no observable effect, because 
// the randonmane identifier is already defined 
randomname = {}; 
randomname.attribute = 'something'; 

randomname(); // TypeError, randomname is not callable. 

Khi nhập vào một bối cảnh thực hiện, Variable Instantiation quá trình (aka Declaration Binding Instantiation trong ES5) định nghĩa các thuộc tính trên Activation Object (AO, đây là đối tượng không thể truy cập có chứa số nhận dạng của biến, khai báo chức năng và đối số hàm trong phạm vi địa phương) theo thứ tự sau:

  1. FormalParameterList định danh (đối với Function Code)
  2. FunctionDeclaration định danh
  3. VariableDeclaration định danh

Một VariableDeclaration sẽ không ghi đè lên một định danh đã được đã được xác định trong AO (ví dụ bởi một trong hai bước đầu tiên), nhưng nhiệm vụ sẽ thực hiện trong thời gian chạy.

Ví dụ:

(function (foo) { 
    var foo; // doesn't affect the existing `foo` identifier 
    return typeof foo; 
    function foo() {} 
})('string'); // yields "function" 

Nhưng nếu chuyển nhượng được thực hiện, giá trị của số nhận dạng sẽ được thay thế, ví dụ:

(function (foo) { 
    var foo = {}; 
    return typeof foo; 
    function foo() {} 
})('string'); // yields "object"!! 

Trong ví dụ trên, khi hàm được gọi , nhưng trước khi thực thi mã, số nhận dạng foo được thiết lập trên Đối tượng kích hoạt (còn gọi là Đối tượng biến).

Đầu tiên nó được gán giá trị của tham số chính thức, giá trị 'string', sau đó tất cả FunctionDeclaration 's trên Body Chức năng được kiểm tra, một hàm có tên foo được tìm thấy, sau đó nhận dạng foo sẽ trỏ đến chức năng đó.

Sau đó, tất cả các Tuyên bố biến được kiểm tra, chúng tôi có một mã định danh là foo, nhưng giá trị của nó được tôn trọng trong thời gian này - nhất là hàm chưa được thực thi.

Tại thời điểm này, hàm đã sẵn sàng để được thực hiện, môi trường từ vựng và biến của nó được thiết lập.

Điều đầu tiên sẽ được thực thi trong hàm, là nhiệm vụ foo = {};, thay thế tham chiếu đến hàm mà chúng tôi đã có trước đó.

Tại sao nó hoạt động khác trên các trình duyệt khác và Firefox?

Bởi vì:

  1. console của Firebug wraps your code trước khi đánh giá nó.
  2. Việc triển khai Mozilla xác định một Function Statement

Kể từ Firebug đánh giá mã của gói bên trong một tuyên bố with, điều này gây ra FunctionDeclaration được đánh giá trong tuyên bố bối cảnh -a Chức năng của Mozilla Câu lệnh.

Để hiển thị hành vi của báo cáo kết quả triển khai chức năng trên Mozilla, xem xét ví dụ sau:

if (true) { 
    function foo() { return 'true!';} 
} else { 
    function foo() { return 'false??!';} 
} 

foo(); 

Trong Mozilla bạn sẽ nhận được 'true!', trong khi ở hiện thực khác bạn sẽ nhận được 'false??!' - ngay cả trên tức là-.

Đó là do định nghĩa hàm được thực hiện tại thời gian chạy, trong ngữ cảnh Statement (ở bên nhánh thực của if), trong khi thực hiện khác, khai báo hàm được đánh giá tại thời gian phân tích.

Ví dụ trên thực tế nên tạo ra một ngoại lệ SyntaxError trên bất kỳ thực hiện, nhưng điều đó không xảy ra trên bất kỳ trong số họ ...

Một FunctionDeclaration nên được cho phép mà thôi, trong mã toàn cầu hoặc trực tiếp trong FunctionBody của một hàm.

A lot ofpeople sử dụng thay thế cho nhau các điều khoản Tuyên bố chức năng và tuyên bố chức năng nhưng điều đó hoàn toàn sai, ECMAScript không xác định Tuyên bố hàm, là non-standard feature.

Các đặc điểm kỹ thuật có ngắn gọn note về vấn đề này:

LƯU Ý: Nhiều triển khai ứng dụng rộng rãi của ECMAScript được biết để hỗ trợ việc sử dụng các FunctionDeclaration là báo cáo. Tuy nhiên có những thay đổi quan trọng và không thể hòa giải giữa các triển khai trong ngữ nghĩa được áp dụng cho các FunctionDeclarations như vậy. Bởi vì sự khác biệt không thể hòa giải, việc sử dụng một FunctionDeclaration như là một tuyên bố kết quả trong mã đó là không đáng tin cậy di động giữa các triển khai thực hiện. Chúng tôi khuyên rằng việc triển khai ECMAScript hoặc không cho phép sử dụng chức năng này hoặc đưa ra cảnh báo khi gặp phải việc sử dụng đó. Các phiên bản tương lai của ECMAScript có thể xác định các phương tiện di động thay thế để khai báo các hàm trong ngữ cảnh Statement.

Cố gắng chạy mã của bạn trong bối cảnh thực hiện toàn cầu -in một đơn giản <script> phần- và bạn sẽ thấy nó sụp đổ cũng trên Firefox:

<script type="text/javascript"> 
    var randomname = {}; 
    randomname.attribute = 'something'; 

    function randomname(){ 
    alert(randomname.attribute); 
    } 
    randomname(); 
</script> 

Bạn có thể tìm thấy những ví dụ trên here, hãy chắc chắn để mở giao diện điều khiển của Firebug và bạn sẽ thấy cùng lỗi mà bạn gặp phải trên các trình duyệt khác.

+1

Tất cả chi tiết thực hiện phức tạp của mưa đá. Và tôi nghĩ tôi đã biết về Javascript. Mặc dù một lần nữa tôi nghĩ rằng các spec chính thức được nó sai và không có ý định ngừng sử dụng chức năng báo cáo trong các chức năng khác miễn là nó dường như không gây ra vấn đề (và cho đến nay tôi đã không nhìn thấy bất kỳ). – MooGoo

3

function randomname() của bạn đang xác định lại số nhận dạng randomname, do đó mất tham chiếu đến đối tượng bạn đã tạo trước đó. Nó có thể nhìn rõ ràng hơn như thế này:

var randomname = {}; 
randomname.attribute = 'something'; 

var randomname = function() { 
    alert(randomname.attribute); 
}; 

randomname(); 

Người ta thích làm:

var a = 5; 
var a = [20, 30]; 

console.log(a); // returns [20, 30] 
+0

Khi sử dụng 'hàm randomname() {}' trái với 'var randomname = function() {}' có hành vi khác nhau. Trước đây ném một TypeError, trong khi sau này hoạt động chính xác - cảnh báo với undefined. Tôi không nghĩ chúng tương đương nhau. Đã thử nó trong giao diện điều khiển WebKit. EDIT: Không có lỗi được ném trong FF. Phải là lỗi giao diện điều khiển WebKit. –

+0

@Daniel: Đang kiểm tra trong bảng điều khiển Chrome, bạn đã đúng. Ví dụ về OP trả về 'Type Error'. Không xảy ra trong Firebug. Trông giống như một lỗi WebKit với tôi. –

+0

@Daniel Vassallo: Tôi biết sự khác biệt, nhưng Chrome đang ném một lỗi khi không sử dụng phép gán biến cho định nghĩa hàm. Đây là những gì tôi đang cố gắng: http://pastebin.com/KzXQjLny –

2
function randomname(){ 
    alert(randomname.attribute); 
} 

là gần giống như thế này:

var randomname = function() { 
    alert(randomname.attribute); 
} 

Đó không phải là 100% giống hệt nhau, vì với cú pháp đầu tiên bạn có thể tham khảo các hàm "trong tương lai", nhưng về cơ bản nó hoạt động như thế nào. Chỉ có một không gian tên cho các hàm và các biến, vì các hàm được gán cho các biến.

+1

+1 ... Tôi nghĩ rằng "chức năng trong tương lai" điều được gọi là * cẩu * :) –

+0

cảm ơn về "cẩu" và "chức năng trong tương lai" Tôi đã không về điều này cho đến bây giờ –

+1

Thật kỳ lạ, trong Chrome cả hai dường như không tương đương. Ví dụ đầu tiên sẽ ném một 'TypeError'. Tôi tin rằng những gì bạn đăng là hành vi chính xác, nhưng chỉ cần một người đứng đầu lên để một người nào đó không bị cắn bởi "lỗi này". –

0

tha thứ cho câu trả lời của người đi bộ. câu hỏi của bạn hơi khó hiểu, hay đây là một câu hỏi phức tạp. Trong dòng thứ hai bạn đã viết

var randomname.attribute.... 

nếu đó là quan điểm của bạn, thì đó là tuyên bố bất hợp pháp và chắc chắn sẽ ném ngoại lệ. Nhưng nếu quan điểm của bạn là về dòng thứ tư nơi bạn tái sử dụng cùng một tên.

lưu ý rằng bạn đã viết

function randomname(){...} 

thay vì

var randomname = function(){...} 

Tôi không biết tại sao, nhưng bởi vì bạn sử dụng một chức năng trong tương lai, bạn sẽ không có thể ghi đè tên từ trước. do đó tên ngẫu nhiên sẽ vẫn là một băm thay vì một hàm, do đó ném một ngoại lệ.

Câu hỏi của tôi là, vậy điều gì sẽ xảy ra với hàm randomname? Làm thế nào chúng ta có thể gọi nó? Nó là một tài nguyên lãng phí? Theo nguyên tắc chung, tôi luôn sử dụng các mẫu

var randomname = function{..} 

vì vậy tôi luôn đảm bảo rằng xung đột tên sẽ không xảy ra vì vậy tôi chưa bao giờ gặp phải điều này.

1

chức năng cũng thực sự là một đối tượng (đầu tiên đối tượng lớp) trong JavaScript.

Vì vậy, bạn có thể làm điều gì đó như thế này.

var human = function(){ 
    alert("Hi"); 
}; 

// which is perfectly normal 

//but then 

human.name="Anubhav"; 

Và sau đó bạn có thể làm như sau:

human();//works 
alert(human.name);//works 
0

Tôi biết đây là một bài cũ, nhưng tôi tìm thấy một ví dụ về cách thức hoạt động.

Trong thực tế, tôi tin rằng sequelize.js hiện điều đó với đoạn mã sau:

var STRING = function(length, binary) { 
    if (this instanceof STRING) { 
    this._binary = !!binary 
    if (typeof length === 'number') { 
     this._length = length 
    } else { 
     this._length = 255 
    } 
    } else { 
    return new STRING(length, binary) 
    } 
} 

STRING.prototype = { 
    get BINARY() { 
    this._binary = true 
    return this 
    }, 
    get type() { 
    return this.toString() 
    }, 
    toString: function() { 
    return 'VARCHAR(' + this._length + ')' + ((this._binary) ? ' BINARY' : '') 
    } 
} 

Object.defineProperty(STRING, 'BINARY', { 
    get: function() { 
    return new STRING(undefined, true) 
    } 
}) 

Bạn có thể nhìn thấy nó trong tài liệu của họ với nhiều loại dữ liệu: http://sequelizejs.com/docs/latest/models#block-2-line-0. Thông báo Sequelize.STRINGSequelize.STRING(1234)

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