方法汇总:
- 使用原型链继承
function Person(name,age){
this.name = name;
this.age = age;
}
function Strdent(score){
this.score = score;
}
Student.prototype = new Person('marongxin','22');
//如果给原型添加方法、属性,必须先改变原型指向再添加
Student.prototype.eat = function(){
console.log('eat');
}
//由于改变原型指向时直接初始化了属性,实例继承而来的属性的值是相同的
- 借用构造函数继承
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log('eat');
}
function Student(name,age,score){
Person.call(this,name,age);
this.score = score;
}
//无法使用超类原型上的方法/属性
//解决了使用原型链继承方式的缺陷——继承过来的属性的值相同的问题
- 组合继承(原型链继承+借用构造函数继承,建议使用的继承方法)
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.eat = function(){
console.log('eat');
}
function Student(name,age,score){
//借用构造函数继承:解决实例继承得来的属性的值相同问题
Person.call(this,name,age);
this.score = score;
}
//改变原型指向:原型链继承
Student.prototype = new Person()//没有传递参数
- 拷贝继承:直接遍历对象的属性/方法复制到另一个对象中
//特征:使用for-in 遍历,然后赋值给另一对象
function Person(abc) {
this.abc = abc;
}
Person.prototype.age = 21;
Person.prototype.play = function () {
console.log('play');
}
let p1 = new Person(25)
console.log(Object.keys(p1)); //['abc']
let p2 = {}; // 浅拷贝,,在堆上两个空间(p1,p2),
for (let key in p1) { //['abc','age','play']
p2[key] = p1[key];
}
console.log(Object.keys(p2)); //['abc','age','play']
注意对象
- js 不是面向对象的语言,是基于对象的语言
- 原型的作用:
- s是一门动态语言,对象使用了.操作符,那么对象就有了这个属性,但是这个属性没有赋值,会返回undefined,而不是报错
console.log(p1.abc) //undefined
console.log(abc) // Reference Error
- 实例对象中有__proto__(供浏览器使用)属性;构造函数中有prototype(供程序员使用)属性
p1.__proto__ == Person.prototype //true
Person.prototype.constructor == Person // true
- prototype是对象,这种对象中也有__proto__指向的应该是某个构造函数的的prototype
- 原型链:实例对象和原型对象之间的关系是通过实例的__proto__联系起来的,这个关系就是原型链
- Object.keys(p1)//获取p1的所有可枚举的实例属性
- 目前,只有Chrome Safari Firefox 支持__proto__属性
- 当读取一个属性时,首先会在实例中搜索该属性,如果没有找到,会沿着原型链向上查找
- 所有的SuperType继承自Object。
Object.prototype = null
各种继承方式分析
- 原型链继承(原先指向SuperType的一个实例)
- 在改变原型指向的同时实例化属性,不同实例继承而来的属性的值是一样的
- 如果属性是引用类型,那么一个实例更改了改属性,另一个实例的该属性也会随之更改
- 在实践中很少使用原型链继承
- 借用构造函数继承——使用call()或者apply()在新创建的对象上执行构造函数
- 子类型构造函数可以先超类型构造函数传递参数,解决了原型链继承方式继承而来的属性值相同的问题
- 超类型的原型中定义的方法、属性,对子类型是不可见的
- 很少单纯使用构造函数实现继承
- 组合继承(原型链继承+借用构造函数继承)
- 思路是通过原型链实现对原型属性和方法的继承,使用构造函数实现对实例属性、方法的继承
- 避免了原型链继承、借用构造函数继承的缺点,融合了优点