Tổng quan về Prototype của JavaScript Một bài viết JavaScript đơn giản nhưng sẽ cung cấp cho bạn một cái nhìn tổng quan và cơ bản về prototype trong JavaScript cùng với vài ví dụ mẫu JavaScript.

Nhãn: tổng quan về Prototype, cơ bản về prototype, prototype trong JavaScript

Miễn phí web hosting 1 năm đầu tại iPage

Nếu bạn vẫn còn đang tìm kiếm một nhà cung cấp hosting đáng tin cậy, tại sao không dành chút thời gian để thử với iPage, chỉ với không quá 40.000 VNĐ/tháng, nhưng bạn sẽ được khuyến mãi kèm với quà tặng trị giá trên 10.000.0000 VNĐ nếu thanh toán cho 24 tháng ~ 900.000 VNĐ?

Có trên 1 triệu khách hàng hiện tại của iPage đã & đang hài lòng với dịch vụ, tuyệt đối chắc chắn bạn cũng sẽ hài lòng giống họ! Quan trọng hơn, khi đăng ký sử dụng web hosting tại iPage thông qua sự giới thiệu của chúng tôi, bạn sẽ được hoàn trả lại toàn bộ số tiền bạn đã sử dụng để mua web hosting tại iPage. Wow, thật tuyệt vời! Bạn không phải tốn bất kì chi phí nào mà vẫn có thể sử dụng miễn phí web hosting chất lượng cao tại iPage trong 12 tháng đầu tiên. Chỉ cần nói chúng tôi biết tài khoản của bạn sau khi đăng ký.

Nếu muốn tìm hiểu thêm về ưu / nhược điểm của iPage, bạn hãy đọc đánh giá của ChọnHostViệ nhé!
Thử iPage miễn phí cho năm đầu tiên NGAY

JavaScript's prototype object generates confusion wherever it goes. Seasoned JavaScript professionals, even authors frequently exhibit a limited understanding of the concept. I believe a lot of the trouble stems from our earliest encounters with prototypes, which are almost always related to new, constructor and the very misleading prototype property attached to functions. In fact prototype is a remarkably simple concept. To understand it better, we just need to forget what we 'learned' about constructor prototypes and start again from first principles.

What is a prototype?

A prototype is an object from which other objects inherit properties

Can any object be a prototype?


Which objects have prototypes?

Every object has a prototype by default. Since prototypes are themselves objects, every prototype has a prototype too. (There is only one exception, the default object prototype at the top of every prototype chain. More on prototype chains later)

OK back up, what is an object again?

An object in JavaScript is any unordered collection of key-value pairs. If its not a primitive (undefined, null, boolean, number or string) its an object.

You said every object has a prototype. But when I write ({}).prototype I get null. Are you crazy?

Forget everything you learned about the prototype property - it's probably the biggest source of confusion about prototypes. The true prototype of an object is held by the internal [[Prototype]] property. ECMA 5 introduces the standard accessor Object.getPrototypeOf(object) which to-date is only implemented in Firefox and Chrome. In addition all browsers except IE and Opera support the non-standard accessor __proto__. Failing that we need to ask the object's constructor for its prototype property.

01var a = {};
03//Firefox 3.6 and Chrome 5
04Object.getPrototypeOf(a); //[object Object]
06//Firefox 3.6, Chrome 5 and Safari 4
07a.__proto__; //[object Object]
09//all browsers
10a.constructor.prototype; //[object Object]

Ok fine, but false is a primitive, so why does false.__proto__ return a value?

When a primitive is asked for it's prototype it will be coerced to an object.

1//(works in IE too, but only by accident)
2false.__proto__ === Boolean(false).__proto__; //true

I want to use prototypes for inheritance. What do I do now?

It rarely makes sense to set a prototype for one instance and only one instance, since it would be equally efficient just to add properties directly to the instance itself. I suppose if we have created a one off object which we would like to share the functionality of an established object, such as Array, we might do something like this (in __proto__ supporting browsers).

1//unusual case and does not work in IE
2var a = {};
3a.__proto__ = Array.prototype;
4a.length; //0

But the real power of prototype is seen when multiple instances share a common prototype. Properties of the prototype object are defined once but inherited by all instances which reference it. The implications for performance and maintenance are obvious and significant.

So is this where constructors come in?

Yes. Constructors provide a convenient cross-browser mechanism for assigning a common prototype on instance creation.

Just before you give an example I need to know what this constructor.prototype property is all about?

OK. Firstly JavaScript makes no distinction between constructors and other functions, so every function gets a prototype property. Conversely, anything that is not a function does not have such a property.

01//function will never be a constructor but it has a prototype property anyway
02Math.max.prototype; //[object Object]
04//function intended to be a constructor has a prototype too
05var A = function(name) {
06 = name;
08A.prototype; //[object Object]
10//Math is not a function so no prototype property
11Math.prototype; //null

So now the definition: A function's prototype property refers to the object that will be assigned as the prototype to all instances created when this function is used as a constructor.

It's important to understand that a function's prototype property has nothing to do with it's actual prototype.

1//(example fails in IE)
2var A = function(name) {
3 = name;
6A.prototype == A.__proto__; //false
7A.__proto__ == Function.prototype; //true - A's prototype is set to its constructor's prototype property

Example please?

You've probably seen and used this a hundred times but here it is once again, maybe now with added perspective.

01//Constructor. <em>this</em> is returned as new object and its internal [[prototype]] property will be set to the constructor's default prototype property
02var Circle = function(radius) {
03    this.radius = radius;
04    //next line is implicit, added for illustration only
05    //this.__proto__ = Circle.prototype;
08//augment Circle's default prototype property thereby augmenting the prototype of each generated instance
09Circle.prototype.area = function() {
10   return Math.PI*this.radius*this.radius;
13//create two instances of a circle and make each leverage the common prototype
14var a = new Circle(3), b = new Circle(4);
15a.area().toFixed(2); //28.27
16b.area().toFixed(2); //50.27

That's great. And if I change the constructor's prototype, even existing instances will have access to the latest version right?

Well....not exactly. If I modify the existing prototype's property then this is true, because a.__proto__ is a reference to the object defined by A.prototype at the time it was created.

01var A = function(name) {
02 = name;
05var a = new A('alpha');; //'alpha'
08A.prototype.x = 23;
10a.x; //23

But if I replace the prototype property with a new object, a.__proto__ still references the original object.

01var A = function(name) {
02 = name;
05var a = new A('alpha');; //'alpha'
08A.prototype = {x:23};
10a.x; //null

What does a default prototype look like?

An object with one property, the constructor.

1var A = function() {};
2A.prototype.constructor == A; //true
4var a = new A();
5a.constructor == A; //true (a's constructor property inherited from it's prototype)

What does instanceof have to do with prototype?

The expression a instanceof A will answer true if a's prototype falls within the same prototype chain as A's prototype property. This means we can trick instanceof into failing

01var A = function() {}
03var a = new A();
04a.__proto__ == A.prototype; //true - so instanceof A will return true
05a instanceof A; //true;
07//mess around with a's prototype
08a.__proto__ = Function.prototype;
10//a's prototype no longer in same prototype chain as A's prototype property
11a instanceof A; //false

So what else can I do with prototypes?

Remember I said that every constructor has a prototype property which it uses to assign prototypes to all instances it generates? Well that applies to native constructors too such as Function and String. By extending (not replacing!) this property we get to update the prototype of every instance of the given type.

I've used this technique in numerous previous posts to demonstrate function augmentation. For example the tracer utility I introduced in my last post needed all string instances to implement times, which returns a given string duplicated a specified number of times

1String.prototype.times = function(count) {
2    return count < 1 ? '' : new Array(count + 1).join(this);
5"hello!".times(3); //"hello!hello!hello!";
6"please...".times(6); //"please...please...please...please...please...please..."

Tell me more about how inheritance works with prototypes. What's a prototype chain?

Since every object and every prototype (bar one) has a prototype, we can think of a succession of objects linked together to form a prototype chain. The end of the chain is always the default object's prototype.

1a.__proto__ = b;
2b.__proto__ = c;
3c.__proto__ = {}; //default object
4{}.__proto__.__proto__; //null

The prototypical inheritance mechanism is internal and non-explicit. When object a is asked to evaluate property foo, JavaScript walks the prototype chain (starting with object a itself), checking each link in the chain for the presence of property foo. If and when foo is found it is returned, otherwise undefined is returned.

What about assigning values?

Prototypical inheritance is not a player when property values are set. = 'bar' will always be assigned directly to the foo property of a. To assign a property to a prototype you need to address the prototype directly.

And that about covers it. I feel I have the upper hand on the prototype concept but my opinion is by no means the final word. Please feel free to tell me about errors or disagreements.

Where can I get more information on protoypes?

I recommend this excellent article by Dmitry A. Soshnikov

JavaScript theo ngày

Google Safe Browsing McAfee SiteAdvisor Norton SafeWeb Dr.Web