Prototype(原型)
含义:我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以由特定类型的所有实例共享的属性
属性的作用
Prototype通过调用构造函数而创建那个对象实例的原型对象
当实例对象本身没有某个属性或方法的时候,会到构造函数的prototype属性指向的对象,去寻找该属性或方法;如果实例对象自身就有某个属性或方法,它就不会再去原型对象寻找这个属性或方法。
demo:
function Animal (name){
this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('大毛');
var cat2 = new Animal('二毛');
cat1.color // 'white'
cat2.color // 'white'
构造函数Animal的prototype对象,就是实例对象 cat1和cat2的原型对象,在原型对象上添加一个color属性。结果,实例对象都能读取该属性。
原型对象的属性不是实例对象自身的属性。只要修改原型对象,变动就立刻会体现在所有实例对象上。
总结:原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的含义,而实例对象可以视作从原型对象衍生出来的子对象。即让所有实例对象共享它包含的属性和方法,不必在构造函数中定义对象实例的信息
优点:可以让所有实例对象共享它包含的属性和方法
原型链
“原型链”的作用是,读取对象的某个属性时,JavaScript引擎先寻找对象本身的属性,如果找不到,就到它的原型去找,如果还是找不到,就到原型的原型去找。如果直到最顶层的Object.prototype还是找不到,则返回undefined。
如果对象自身和它的原型,都定义了一个同名属性,那么优先读取对象自身的属性,这叫做“覆盖”
代码:
<script type="text/javascript">
var Person = function () { };
var p = new Person();
script>
new的过程可以分为三步:
var p={}; 也就是说,初始化一个对象p。
p.proto=Person.prototype;
Person.call(p);也就是说构造p,也可以称之为初始化p。
proto是每个对象都会在其内部初始化一个属性,当我们访问一个对象的属性时,如果这个对象内部不存在这个属性,那么他就会去proto里找这个属性,这个proto又会有自己的proto,于是就这样一直找下去,也就是我们平时所说的原型链的概念。
相关函数
instanceof运算符
instanceof运算符返回一个布尔值,表示指定对象是否为某个构造函数的实例。只能用于对象,不适用原始类型的值。
var v = new Vehicle();
v instanceof Vehicle //true
//等同于
Vehicle.prototype.isPrototypeOf(v)
instanceof运算符的左边是实例对象,右边是构造函数。它的运算实质是检查右边构建函数的原型对象,是否在左边对象的原型链上。对于那些不存在原型链的对象,就无法判断。
hasOwnProperty函数
hasOwnProperty函数判断一个对象是否包含自定义属性而不是原型链上的属性,处理属性但是不查找原型链的函数。
Date.hasOwnProperty('length')
// true
Date.hasOwnProperty('toString')
// false
getOwnPropertyNames
返回一个数组,成员是对象本身的所有属性的键名,不包含继承的属性键名。
Object.getOwnPropertyNames(Date)
// ["parse", "arguments", "UTC", "caller", "name", "prototype", "now", "length"]
Object.getOwnPropertyNames方法返回所有键名。只获取那些可以枚举的属性,使用Object.keys方法。
isPrototypeOf()
对象实例的isPrototypeOf方法,用来判断一个对象是否是另一个对象的原型。
var o1 = {};
var o2 = Object.create(o1);
var o3 = Object.create(o2);
o2.isPrototypeOf(o3) // true
o1.isPrototypeOf(o3) // true
//上面代码表明,只要某个对象处在原型链上,isPrototypeOf都返回true。
Object.prototype.isPrototypeOf({}) // true
Object.prototype.isPrototypeOf([]) // true
Object.prototype.isPrototypeOf(/xyz/) // true
Object.prototype.isPrototypeOf(Object.create(null)) // false
_
proto_
_
proto_
可以改写某个对象的原型对象。
var obj = {};
var p = {};
obj.__proto__ = p;
Object.getPrototypeOf(obj) === p // true
将p对象设为obj对象的原型。
尽量少用这个属性,而是用Object.getPrototypeof()(读取)和Object.setPrototypeOf()(设置),进行原型对象的读写操作。
获取原型对象方法的比较
三种方法:
- obj.
_
proto_
- obj.constructor.prototype
- Object.getPrototypeOf(obj)
前两种都不是很可靠。最新的ES6标准规定,_
proto_
属性只有浏览器才需要部署,其他环境可以不部署。而obj.constructor.prototype在手动改变原型对象时,可能会失效。
推荐使用第三种Object.getPrototypeOf方法,获取原型对象。
var o = new Object();
Object.getPrototypeOf(o) === Object.prototype
// true