原型链是如何形成的?
每个子类的实例对象都包含一个内部属性 _proto_ 属性,该属性包含一个指针,指向父类的prototype,即原型对象。若父类的原型对象的 _proto_ 属性再指向上层函数,即爷爷类的prototype,层层往上,就成了原型链。
JS 中每一个函数都存在原型对象属性 prototype,并且只有函数才有原型对象 prototype 属性
所有函数的默认原型都是Object 的实例
实现继承的几种方法,优缺点?
一、原型链继承法
子类的 prototype 属性指向父类实例
代码示例
function Parent(){
this.name = ['小黑','小白'];
}
Parent.prototype.getName = function(){
console.log(this.name);
}
function Child(){
}
Child.prototype = new Parent(); //关键代码
缺点
- 父类引用类型的属性,会被所有实例共享,例如:
var myChild = new Child();
var herChild = new Child();
myChild.name.push('小黄');
console.log(myChild.name); // ['小黑','小白','小黄'];
console.log(herChild.name); // ['小黑','小白','小黄'];
- 创建子类实例时,不能像父类传参
二、借用构造函数继承法(经典继承)
在子类构造函数内通过call、apply,执行父类构造函数
代码示例
function Parent(){
this.name = ["小黑","小白"];
}
function Child(){
Parent.call(this);
}
var myChild = new Child();
var herChild - new Child();
myChild.name.push("小黄");
console.log(myChild.name); // ["小黑","小白","小黄"]
console.log(myChild.name); // ["小黑","小白"]
优点
- 避免引用类型的属性被所有实例共享
- 可以在子类实例化的时候,向父类传递参数,例如:
function Parent(name){
this.name =name;
}
function Child(name){
Parent.call(this,name);
}
var myChild = new Child('小黑');
var herChild = new Child('小白');
console.log(myChild.name); // 小黑
console.log(herChild.name); //小白
三、组合继承法
运用原型链继承和经典继承(借用构造函数继承法)
优点:融合原型链继承和借用构造函数继承的优点,是javascript中最常用的继承方式
代码示例
function Parent (name){
this.name = name;
}
Parent.prototype.getName = function(){
console.log(name)
}
function Child(){
Parent.call(this,name);
this.age = 20;
}
Child.prototype = new Parent();
Child.prototype.constructor = Child;//构造函数指向自身