【有书共读】JavaScript面向对象编程指南 5
原型属性 prototype
在函数定义是,被创建的属性中包括有prototype,这就是原型属性。其初始值是一个空对象。如:
可通过foo.prototype = {}添加自身属性。
添加方法与属性
1、在构建构造函数时,添加方法与属性:
2.通过原型prototype添加属性
原型prototype添加属性可以逐条添加,也可以定义对象覆盖之前的原型上。
使用原型的方法与属性
向prototype 属性添加方法与属性后,可以直接使用构造器创建对象,从而访问添加的属性与方法。
原型具有实时性,我们可以随时修改prototype属性,而且同一构造器创建的所有对象的prototype属性也会同时改变。
如为Gadget添加新的方法
而之前Gadget创建的newtoy对象还是能访问新增的方法:
自身属性与原型属性
当访问对象的某个属性时,JavaScript引擎会遍历该对象的所有属性,并查找该属性,若是找到则返回其值。如果没找到,则会查询该对象构造函数的原型,若是找到则使用属性。若是找不到,则继续找原型的原型,直到最高级的父级对象object。
如newtoy对象,name属性在newtoy对象中,但是rating在prototype中
> newtoy.name;
"webcam"
> newtoy.rating;
3
利用自身属性重写原型属性
对象自身属性优先级高于原型属性。当同一个属性名,同时出现在对象自身的属性与原型时,会优先取对象自身属性。
可以通过hasOwnProperty()方法判断属性是自身还是原型的。
> toy.hasOwnProperty('name');
true
如果删自身属性,则同名的原型属性生效:
> delete toy.name;
true
> toy.name;
"mirror"
> toy.hasOwnProperty('name');
false
属性删除后,也可以随时重建
> toy.name = 'camera';
"camera"
> toy.name;
"camera"
也可通过hasOwnProperty()判断原型属性是属于原型链中的哪个原型。
> toy.toString();
"[object Object]"
> toy.hasOwnProperty('toString');
false
> toy.constructor.hasOwnProperty('toSrting');
false
> toy.constructor.prototype.hasOwnProperty('toString');
false
> Object.hasOwnProperty('toString');
false
> Object.prototype.hasOwnProperty('toString');
true
枚举属性
可以通过for-in循环显示对象的属性列表,但是不能显示所有。通过枚举propertyIsEnumerable()方法判断对象的某个属性是否可枚举,从而获取对象的显示属性。
若是原型链中的属性可枚举,也可显示出来。但所有原型的属性propertyIsEnumerable()都返回false,包括for-in中可枚举的属性。
function Gadget(name,color){
this.name = name ;
this.color = color;
this.getName = function(){
return this.name;
};
}
Gadget.prototype.price = 100;
Gadget.prototype.rating = 3;
var newtoy = new Gadget('webcam','black');
通过for-in列出对象的所有属性:
通过hasOwnProperty()获取对象自身属性
propertyIsEnumerable对所有非内建对象返回true,内见对象与方法返回false。任何原型链的属性都是不可枚举,但是原型链上的对象,是可枚举的。
> newtoy.propertyIsEnumerable('name');
true
> newtoy.propertyIsEnumerable('constructor');
false
> newtoy.propertyIsEnumerable('price');
false
> newtoy.constructor.prototype.propertyIsEnumerable('price');
true
isPrototypeOf()方法
每个对象都有一个isPrototypeOf()方法。用于判断当前对象是否是另外一个对象的原型。
__proto__链接
在JavaScript环境中,对象存在一个真相先关原型的链接。即是__proto__属性。
> var monkey = {
feeds :'bananas',
breathes : 'air'
};
>function Human(){}
>Human.prototype = monkey;
{feeds: "bananas", breathes: "air"}
>var developer = new Human();
>developer.feeds = 'pizza';
developer.hacks = 'JavaScript';
"JavaScript"
>developer.__proto__ === monkey;
true
注意:__proto__ 只能在学习或调试环境下使用。
扩展内建对象
在JavaScript环境中,内建对象的构造器函数都可以通过对其原型进行扩展。如:定义一个查询数组是否存在某个特定值的方法。
扩展内建对象是非常强大,但是必须谨慎。因为通过原型内建对象的方法属性,若是被他人修改,则容易引起该对象的行为改变,容易导致难以维护。另外原型内建的对象,若是随着JavaScript的发展,变为JavaScript的内置对象,就会导致两者冲突。
此时,我们可以通过方法解决:
>if (typeof String.prototype.trim !== 'function'){
String.prototype.trim = function(){
return this.queryReplace(/^\s+|\s+&/g,'');
}
};
> "hello ".trim();
"hello"
小结:
- 在JavaScript中,所有函数都会拥有一个叫做prototype的属性。默认是为‘空’对象。
- 可在原型对象中添加新的方法属性,也可以自定义对象来完全替换原有的原型对象。
- 通过构造器新建对象时(new),该对象会自动拥有指向prototype属性的链接。可通过prototype属性访问相关原型对象的属性。
- 对象自身属性优先级高于原型对象中的同名属性
- 可通过hasOwnProperty()方法区分对象自身属性与原型属性
- 当原型链接中,访问某个对象的属性,JavaScript引擎会先搜索该对象,若对象中不存在该属性,则会继续搜索其他原型的原型,直到最高父级原型Object.prototype。
- 可对内建的构造器进行扩展,以便所有的对象都能引用添加的功能。在添加相关方法和属性之前,应该检查已有方法是否已存在。这样会增加脚本对未来环境的适应能力。