2011-02-02 32 views
12

Trong JavaScript, this phải luôn được tuyên bố rõ ràng khi truy cập các thuộc tính của nó. Ví dụ:Tại sao không có ẩn trong JavaScript

function Frobber(x) { 
    this.x = x; 
    return this; 
} 

Frobber.prototype.frob = function() { 
    // wrong: 
    return x * x; 
    // right: 
    return this.x * this.x; 
} 

Tôi biết tôi có thể sử dụng with(this) (mà bị phản đối và thường tán thành), nhưng tại sao không phải là thuộc tính của this trong phạm vi tự động? Tôi nghĩ rằng phải có một lý do cho quyết định thiết kế này.

+0

Tôi thực sự không biết nhưng tôi đoán đơn giản chỉ để tăng khả năng đọc. Một dự đoán ngẫu nhiên khác là nó có thể giúp tăng tốc mọi thứ trong độ phân giải thay đổi trong một ngôn ngữ thông dịch? – madmik3

+0

có lẽ nó đã được thiết kế để phạm vi toàn cầu có thể được truy cập dễ dàng ngay cả khi có tấn chuỗi nguyên mẫu ?! – kjy112

+0

@ kjy112: Không chỉ toàn cầu - mọi phạm vi bao quanh. Đặc biệt quan trọng với bao đóng. – delnan

Trả lời

9

Nó tương tự như Python. Lý do khá đơn giản: Bạn không thể thêm điều này, vì nó xung đột với quy tắc phạm vi tìm kiếm mặc định cho các biến không phải cục bộ trong phạm vi bên ngoài. Có thể bằng các ngôn ngữ được gõ tĩnh, vì các thành viên của this được biết đến tại thời gian biên dịch.

Và những gì nếu làm cho nó một quyết định động, chẳng hạn như "x đề cập đến this.x nếu this.x !== undefined và nếu không vào biến x" (hoặc bất kỳ quy tắc khác cho việc này được quyết định tại thời gian chạy)? Điều đó rất nguy hiểm, vì nó có thể đổ bóng các biến cục bộ dựa trên những gì this xảy ra, tức là phá vỡ mã hoàn toàn hợp lệ chỉ cho một số đối tượng nhất định. Một vấn đề khác: Nên undeclaredVar = ... thêm thuộc tính thể hiện mới? Nếu không, đó sẽ là một sự bất đối xứng xấu xí giữa ẩn và rõ ràng this. Nếu nó không tạo thuộc tính thể hiện, bạn sẽ mất khả năng đặt biến toàn cầu và đóng từ các hàm bên trong - không quá nhiều mất mát, nhiều người sẽ nói; nhưng các nhà thiết kế JS dường như đã nghĩ khác, vì họ đã chọn phạm vi toàn cầu làm mặc định.

Tạo thuộc tính thể hiện bóng "biến thường" sẽ ít nguy hiểm hơn, nhưng với phạm vi lồng nhau có nhiều tên, bạn sẽ bị buộc phải sử dụng this. trong hầu hết các trường hợp - vì vậy sẽ ít thắng hơn. Đối với điều này, và/hoặc propably vì lý do khác, các nhà thiết kế coi là một phím tắt infeasible.

1

Nếu x được ngụ ý là this.x, cách bạn truy cập các biến được xác định là tên x?

function Frobber(x) { this.x = x; } 
Frobber.prototype.frob = function() { 
    var x = 'WHAT ABOUT ME'; 
    return x; 
} 
+3

Hoạt động tốt bằng các ngôn ngữ khác. Các biến địa phương thuộc tính đối tượng bóng. – kprevas

+0

Chưa kể, như @ kjy112 đã chỉ ra, các biến từ phạm vi toàn cầu. – harpo

+0

@kprevas: Bất kỳ ngôn ngữ động nào trong số này? Tôi không biết bất kỳ (Python không, Ruby đánh dấu các thuộc tính instance với '@', tôi không có ý tưởng về Perl, các ngôn ngữ Smalltalk-ish sử dụng một cái gì đó giống như 'object slot' theo như tôi biết). – delnan

2

Điều "này" đề cập đến trong Javascript là hoàn toàn một chức năng về cách chức năng hiện tại được gọi.

Nếu nó được gọi là phương thức (tức là với toán tử.) Thì 'this' sẽ được đặt thành đối tượng trước dấu chấm.

Nếu nó được gọi là hàm đơn giản, thì 'this' sẽ là đối tượng chung (thường là cửa sổ).

IIRC nếu bạn sử dụng Function.call, bạn có thể đặt rõ ràng.

Javascript là ngôn ngữ OO nhưng không không có các lớp học và không (nghiêm chỉnh) có phương pháp.

+3

Đúng, nhưng điều này liên quan đến câu hỏi như thế nào? – delnan

+0

Bởi vì những gì 'này' là ràng buộc trong những ví dụ này sẽ phụ thuộc vào cách các chức năng được gọi. –

1

Bạn cần phải xác định rõ ràng "này" vì "cửa sổ" là ngầm thay vì

function SomeFunc(x) { 
    y = x; 
    return this; 
} 

là giống như

function SomeFunc(x) { 
    window.y = x; 
    return this; 
} 
1

Mỗi đối tượng chức năng giới thiệu một không gian tên mới và điền nó với các tham số, biến và khai báo hàm bên trong của nó. Nếu tất cả các thuộc tính của đối tượng this sẽ được tiêm vào cùng một không gian tên này, thì các tên sẽ xung đột. Để ngăn chặn sự va chạm này, bạn phải chắc chắn rằng mỗi tên tham số, tên biến cục bộ hoặc tên khai báo hàm không giống như bất kỳ thuộc tính nào của đối tượng được tham chiếu bởi this.

Vì bạn có thể tự động thêm thuộc tính mới vào đối tượng, bạn cũng phải đảm bảo rằng bất kỳ thuộc tính mới nào bạn thêm vào, không va chạm với tất cả các tham số, biến, ... trong mỗi phương thức đối tượng.

Điều này gần như không thể giải quyết được.

0

Từ JavaScript: The Good Parts (Functions -- Invocation):

Có bốn mô hình gọi trong JavaScript: mô hình phương pháp gọi, mô hình chức năng gọi, mô hình xây dựng gọi, và áp dụng mô hình gọi.

Về cơ bản, mỗi "mẫu" này xác định cách tham chiếu this được xác định. Nếu một hàm được định nghĩa là một phương thức của một đối tượng, thì this sẽ tham chiếu đến đối tượng cha. Nếu hàm không phải là thuộc tính của đối tượng, thì this là đối tượng chung. Nếu hàm được gọi với từ khóa new (tức là làm hàm tạo) thì this là đối tượng mới được tạo. Và cuối cùng, nếu bạn sử dụng phương thức apply() của hàm, tham chiếu của this bị ràng buộc với bất kỳ đối tượng nào bạn chỉ định.

+1

Thật vậy, nhưng 'điều này' vẫn không trả lời được câu hỏi ... – configurator

+0

Làm thế nào nó không trả lời được câu hỏi? Tham chiếu không được định nghĩa cho đến khi bạn gọi hàm, và nó phụ thuộc vào cách bạn gọi hàm như thế nào nó được định nghĩa.Do đó, bạn không thể biết 'this' là gì cho đến khi hàm được gọi. –

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