JavaScript’s prototype objects are always confusing. Even experienced JavaScript experts and even its authors often give a very limited explanation of this concept. I believe the problem comes from our earliest understanding of prototypes. Prototypes are always closely associated with new, constructor and the confusing prototype property. In fact, prototyping is a fairly simple concept. To understand it better, we need to unlearn the construction archetypes we 'learned' and, then, go back to the roots.
What is a prototype?
A prototype is an object that inherits properties from other objects.
Can any object be a prototype?
Yes
Those objects have prototypes?
Every object has a default prototype. Prototypes themselves are objects, and each prototype itself has a prototype. (With one exception, the default object prototype is at the top of each prototype chain, and the other prototypes are at the end of the prototype chain)
Taking a step back, what is an object?
In JavaScript, an object is an arbitrary unordered collection saved as key-value pairs. If it is not a primitive class (undefined, null, boolean.nuber or string), it is an object.
You can think that each object has a prototype. But when I wrote ({}).prototype, I got undefined. Are you crazy?
Forget everything you know about the prototype property - this is probably a source of confusion. The true prototype of an object is the internal [[Prototype]] property. ECMA 5 introduces the standard access method, Object.getPrototypeOf(object ). This latest implementation is supported by Firefox, Safari, Chrome and IE9. In addition, except IE, all browsers support the non-standard access method __proto__. Otherwise, we can only say that the constructor of an object is its prototype Properties.
var a = {}; //Opera 或 IE<=8下失败 Object.getPrototypeOf(a); //[object Object] //IE下失败 a.__proto__; //[object Object] //所有浏览器 //(but only if constructor.prototype has not been replaced and fails with Object.create) a.constructor.prototype; //[object Object]
Very good, false is a primitive type, why does false.__proto__ return a value?
When accessing the prototype of a primitive type, it will be coerced into an object.
//(works in IE<=8 too, due to double-negative) false.__proto__ === Boolean(false).__proto__; //true
I want to implement inheritance using prototypes, what should I do now?
It is almost meaningless to add prototype properties to an instance. Unless there is one situation, that is, it is very efficient to add properties directly to the instance itself. Suppose we already have an object and want to share the existing object. Function. For example Array, we can do this
//fails in IE<=8 var a = {}; a.__proto_ = Array.prototype; a.length; //0
But we can see that the real power of prototypes lies in multiple instances sharing the same prototype. Properties of a prototype object are defined once and are inherited by all instances it references. The improvement in performance and program maintainability of using prototypes is obvious. So is this the reason for the constructor? Yes, constructors provide a convenient cross-browser mechanism for common prototype assignment on instance creation. .
Before giving an example, I need to know what the constructor.prototype property does?
Well, first of all, JavaScript does not distinguish between constructors and other methods, so every method has a prototype attribute. On the contrary, anything that is not a method does not have such attributes.
//永远不是构造函数的方法,无论如何都是有prototype属性的 Math.max.prototype; //[object Object] //构造函数也有prototype属性 var A = function(name) { this.name = name; } A.prototype; //[object Object] //Math不是一个方法,所以没有prototype属性 Math.prototype; //null
Now you can define: The prototype attribute of a method is the prototype object assigned to the instance when this method is used as a constructor to create an instance.
It is very important to understand that the prototype attribute of a method has nothing to do with the actual prototype.
//(在IE中会失败) var A = function(name) { this.name = name; } A.prototype == A.__proto__; //false A.__proto__ == Function.prototype; //true - A的prototype是它的构造函数的prototype属性
Can you give an example?
You may have seen or used the following code hundreds of times, but here it is again, but there may be something new.
//构造器. <em>this</em> 作为新对象返回并且它内部的[[prototype]]属性将被设置为构造器默认的prototype属性 var Circle = function(radius) { this.radius = radius; //next line is implicit, added for illustration only //this.__proto__ = Circle.prototype; } //扩充 Circle默认的prototype对象的属性因此扩充了每个由它新建实例的prototype对象的属性 Circle.prototype.area = function() { return Math.PI*this.radius*this.radius; } //创建Circle的两个示例,每个都会使用相同的prototype属性 var a = new Circle(3), b = new Circle(4); a.area().toFixed(2); //28.27 b.area().toFixed(2); //50.27
This is great. If I change the prototype property of the constructor, can even existing instance objects immediately access the new prototype version?
Hmm... not really. If I modify the attributes of an existing prototype, then this is indeed the case, because a.__proto__ refers to the object defined by A.prototype when the object is created.
var A = function(name) { this.name = name; } var a = new A('alpha'); a.name; //'alpha' A.prototype.x = 23; a.x; //23
But if I replace the prototype attribute with a new object, a.__proto__ still points to the original object.
var A = function(name) { this.name = name; } var a = new A('alpha'); a.name; //'alpha' A.prototype = {x:23}; a.x; //null
What does a default prototype look like?
An object with constructor property.
var A = function() {}; A.prototype.constructor == A; //true var a = new A(); a.constructor == A; //true (a 的constructor属性继承自它的原型)
What is the relationship between instanceof and prototype?
If the prototype attribute of A appears in the prototype chain of a, the expression a instanceof A will return true. This means we can trick instanceof into failing.
var A = function() {} var a = new A(); a.__proto__ == A.prototype; //true - so instanceof A will return true a instanceof A; //true; //mess around with a's prototype a.__proto__ = Function.prototype; //a's prototype no longer in same prototype chain as A's prototype property a instanceof A; //false
那么我还能利用原型干些其它的什么事儿?
记得我曾经说过每一个构造器都拥有一个prototype属性,利用该属性可以将原型赋值给所有由构造器产生的实例?其实这同样适用于本地构造器,例如Function和String。通过扩展(而不是替换)这个属性,我们可以更新每个指定类型对象的prototype。
String.prototype.times = function(count) { return count < 1 ? '' : new Array(count + 1).join(this); } "hello!".times(3); //"hello!hello!hello!"; "please...".times(6); //"please...please...please...please...please...please..."
告诉我更多关于继承与原型是怎么工作的。原型链又是什么东东?
因为每个对象和每个原型(本身)都有一个原型,我们可以想象, 一个接一个的对象连接在一起形成一个原型链。 原型链的终端总是默认对象(object)的原型。
a.__proto__ = b; b.__proto__ = c; c.__proto__ = {}; //默认对象 {}.__proto__.__proto__; //null
原型继承机制是内在且隐式实现的。当对象a要访问属性foo时,Javascript会遍历a的原型链(首先从a自身开始),检查原型链的每一个环节中存在的foo属性。如果找到了foo属性就会将其返回,否则返回undefined值。
直接赋值会咋样?
当直接为对象属性赋值时,原型继承机制就玩不转了。a.foo='bar'会直接赋值给a的foo属性。要想为原型对象的属性赋值,你需要直接定位原型对象的该属性。
关于javascript原型就讲全了。我觉得对于原型概念的理解,我把握的还是比较准确的,但是我的观点无论如何也不是最后的结果。请随便告之我的错误之处或提出和我不一致的观点。