主要利用原型实现继承,主要由下面几种原型链继承,借用构造函数继承,组合继承,运行继承。下面就来详细介绍这几种继承的方式
原型链-继承
ECMAScript中描述了原型链,并将原型链作为实现继承的主要方法.基本思想就是利用原型让一个引用类型继承另一个引用类型的属性和方法。这句话比较晦涩难理解,直接看代码。
function Super() {
this.superProperty = false;
}
Super.prototype.getSuperProperty = function () {
return this.superProperty;
}
function Sub() {
this.subProperty = true;
}
//这句话一定要在Sub.prototype = new Super()后面写,否则被覆盖
Sub.prototype.getSubProperty = function () {
return this.subProperty;
}
Sub.prototype = new Super();
var sub = new Sub();
console.log(sub.getSuperProperty());
//Sub.prototype就是Super实例,sub的原型
console.log(Sub.prototype.isPrototypeOf(sub));
//Super.prototype是Super实例的原型,相当于Super实例继承Super,prototype,而Sub继承Super实例,所以也正确
console.log(Super.prototype.isPrototypeOf(sub));
//可以看出Sub的prototype就是Super实例,Sub.prototype
console.log(Object.getPrototypeOf(sub) == Sub.prototype);
上述代码中,想实现Sub继承Super.通过Sub.prototype = new Super()
实现。
构造函数原型实例之间的关系
可以看到原型链之间的关系:
Sub实例
subProperty
__proto__ = Super实例
superProperty
__proto__ = Super原型
getSuperProperty()
__proto__ = Object 原型
hasOwnProperty
...
__proto__ =undefined
上面就是代码的原型链,当查找一个属性的时候,会沿着原型链进行查找,如果没有查找到,沿着原型链向上查找,直到查到Object.proto 如果还没查找到,则返回undefined.
原型链实现继承的问题:
1.和使用原型创建对象一样,如果是引用类型,会导致属性共享,影响多个实例之间的属性值
2.不想向超类型的构造函数中传递参数
借用构造函数
使用call或者apply,把父构造函数当做普通的函数调用即可。改变其执行的作用域
function Super(name) {
this.name = name;
this.sayName = function () {
console.log(this.name);
}
}
function Sub(name, age) {
Super.call(this, name);
this.age = age;
}
var sub = new Sub('小明',23);
//小明
sub.sayName();
由上图知,上述Sub
的构造函数相当于
function Sub(name, age) {
this.name = name;
this.sayName = functio(){
console.log(this.name)
};
this.age = age;
}
借用构造函数问题
1.既然使用的时构造函数,那么就没法复用方法和属性
组合继承
有时也叫伪经典继承,将原型链和借用构造函数组合在一起.即实现了属性的共享,又保证了每个实例都有自己的属性。组合继承避免了原型链和借用构造函数的缺陷,融合了他们的优点,成为Javascript中最常用的继承模式。
function Super(name) {
this.name = name;
this.friends = [];
}
Super.prototype.sayName = function () {
console.log(this.name);
}
function Sub(age, name) {
Super.call(this, name);
this.age = age;
}
Sub.prototype = new Super();
//构造函数要重新指定
Sub.prototype.constructor = Sub;
var sub1 = new Sub(20, '小明');
var sub2 = new Sub(30, '小华');
sub1.friends.push('小亮');
sub2.friends.push('小李');
console.log(sub1.friends);//[ '小亮' ]
console.log(sub2.friends);//[ '小李' ]
sub1.sayName();//小明
sub2.sayName();//小华
原型式继承
道格拉斯.克罗克福 在2006年写了一篇文章,题为 Prototypal Inheritance in javaScript(Javascript 中的原型继承)。这种方法可以借助原型基于已有的对象创建新对象,同时还不必因此创建自定义类型。
function object(o) {
function F() {}
F.prototype = o;
return new F();
}
其实和原型链继承一样,只不过不需要每次都要创建自定义类型了。
ECMAScript中的实现了原型式继承,Object.create()
,可以传入两个参数,第一个参数是基于的原型对象,第二个参数是自己的属性。
var baseObject = {
colors: ['red', 'yellow'],
name: 'base'
};
var obj1 = Object.create(baseObject);
//可以定义自己的属性
var obj2 = Object.create(baseObject, {
name: {value: 'obj2'}
});
obj1.colors.push('green');
console.log(obj1.colors);//[ 'red', 'yellow', 'green' ]
console.log(obj2.colors);//[ 'red', 'yellow', 'green' ]
console.log(obj1.name);//base
//自己的属性name覆盖了原型中的属性name
console.log(obj2.name);//obj2
网友评论