关于js的原型其实要从继承说起
什么是继承?
继承主要是为了代码复用。
比如我定义了两个对象(Person和Student),Person里有两个属性name和getName,Student也需要这同样的属性,但又不想重复的写这部分代码,这样就有一个需求,Student需要从Person里继承这两个属性。
var Person = {
name:'person',
getName:function(){
return this.name;
}
}
var Student = {}
那么问题就来了,怎么继承?
在js中实现继承最主要是通过原型链(当然也有其他方法)来实现继承。
那么现在再说说原型
什么是原型
js中的每个对象(null与Object.prototype除外)都和另一个对象关联,这个对象就是原型(prototype),js中的每个对象(null与Object.prototype除外)都从原型中继承属性。【摘自js权威指南】
上面的是比较官方的说法,说通俗点,就是js中每个对象都有一个属性【prototype】指向一个对象,js中每个对象可以使用【prototype】指向的对象中的方法,【prototype】被称为对象的原型。
获得对象的原型可通过Object.getPrototypeOf()方法获得。
var obj = {};
Object.getPrototypeOf(obj) //返回obj的原型
在大多数浏览器中实现了通过__proto__属性来查看原型(ie不支持),并可通过这个属性进行设置。
var obj = {};
obj.__proto__ //返回obj的原型
__proto__是浏览器对对象原型的对外暴露,用以直接查询/设置对象的原型,但IE和Opera还不支持通过
__proto__修改原型非常影响性能,推荐使用Object.create()来实现原型继承
Object.prototype不继承任何属性
原型属性是不可配置的,不可枚举的,不可写的
原型指向那个对象?
这个用几个示例可以说明
var obj1 = {}
obj1.__proto__ === Object.prototype; //返回true
var arr = []
arr.__proto__ === Array.prototype; //返回true
var obj2 = new Object();
obj2.__proto__ === Object.prototype; //返回true
var obj3 = new String('string');
obj3.__proto__ === String.prototype; //返回true
//ES5的方法
var obj4 = Object.create(obj);
//Object.create() 创建一个新对象,其中第一个参数是这个对象的原型,第二个参数对对象的属性进行进一步描述。
obj4.__proto__ === obj; //返回true
原型链
除了Object.prototype,其他原型都是普通对象,普通对象都有原型,最终原型指向Object.prototype,这样的关联关系为原型链。【摘自js权威指南】
例如:
var obj = new Object();
obj.__proto__ === Object.prototype //返回true
//obj的原型直接指向Object.prototype
var obj2 = new String("test");
obj2.__proto__ === String.prototype //返回true
String.prototype.__proto__ === Object.prototype //返回true
//obj2的原型指向String.prototype 然后String.prototype的原型指向Object.prototype
实例为了方便用了
__proto__,虽然大部分浏览器对__proto__都支持,但不推荐使用这个属性,因为还是存在有浏览器不支持的情况。例如上述例子可写为
var obj = new Object(); Object.getPrototypeOf(obj)===Object.prototype //返回true
通过原型继承的属性一般是可枚举的(可以被for/in遍历到),但是某些特殊属性是不可枚举的(例如toString)
用for..in遍历对象的时候,__proto__属性也会被遍历,但是function的prototype属性不会被遍历。
function的prototype
每个function对象都有prototype属性,通过new操作符可实现继承
//新建一个构造函数
function Animail(name){
//初始化代码
this.name = name
}
//设置prototype的属性
Animail.prototype.getName = function(){
return this.name;
}
//通过new实例化一个对象
var cat = new Animail("TOM") //新建一个名字叫TOM的猫
//调用继承的属性方法
cat.getName()//返回'TOM'
其中new操作符相当于进行了以下操作
var cat= {};
obj.__proto__ = ClassA.prototype;
ClassA.call(obj);