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:
FormalParameterList
định danh (đối với Function Code)
FunctionDeclaration
định danh
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ì:
- console của Firebug wraps your code trước khi đánh giá nó.
- 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.
đ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. –