什么是面向对象?JavaScript是面向对象语言吗?
面向对象语言都有一个标志就是类的概念,通过类可以创建多个对象具有相同方法和属性。在JavaScript中没有类的概念,因此他的继承和面向对象语言不太一样,是基于原型对象的一种继承方案。
原型链继承
利用原型让一个引用类型继承另外一个引用类型的方法和属性,通过让待继承的引用类型的原型对象指向另一个类型的实例。
存在的问题:
- 引用值共享问题
- 创建子类时,无法向其超类进行参数传递
不能用对象字面量语法向原型中添加属性(改变原型指针,会切断原型链)
function Child() {
this.name = ['1','2']
}
function Son () {}
Son.prototype = new Child();
var son1 = new Son();// 无法向父类传递参数
var son2 = new Son()
son1.name.push('3')
//son2.name 也会跟着改变
借用构造函数继承
子类的构造函数内部调用父类的构造函数,能够解决传递参数的问题。
不存在原型继承后,函数无法复用
超类原型中的方法无法被继承,所有类型只能使用构造函数中的方法
function Parent() {
this.name = [‘foo’,’bar’];
this.funcLog = function () {
console.log(‘能够使用’);
}
}
//想要继承自Father,通过借用构造函数形式,将this绑定到
function Child(...args) {
Father.apply(this,args)
}
组合继承
使用原型式继承实现对原型中属性和方法的继承,使用构造函数实现对实例属性的继承。
将原型链继承和借用构造函数融为一体,能够实现向父类传递参数并且避免了引用值的问题,是最常用的一种继承方案。function Parent(name) {
this.name = [‘foo’,’bar’];
}
Parent.prototype.func = function () {
console.log(‘继承方法成功’);
}
function Child(…args) {
Parent.call(this,args)
}
Child.prototype = new Parent();
// 由于原型对象被重写,需要将constructor指针归位
Child.prototype.constructor = Child;
原型式继承
借助原型式继承可以对已有的对象创建一个新对象(继承自已有的对象),这种实现继承的方法不需要创建构造函数。
前提是你必须有一个对象作为另外一个对象的继承基础,ES5对该模式封装为:Object.create(对象,属性描述符)
问题:和原型链继承一样的问题,对引用值的共享
function Parent(name) {
this.name = [‘foo’,’bar’];
}
Parent.prototype.func = function () {
console.log(‘继承成功’);
}
function myCreate (o) {
// 中转函数
function F () {}
F.prototype = o;
return new F();
}
寄生组合继承(圣杯继承)
最完美的一种继承方案,需要注意的是重写原型后,需要将constructor 进行归位操作。
问题:调用两次超类构造函数
function _extend (sub,super) {
var _prototype = _create(super);
_prototype.constructor = sub;
sub.prototype = _prototype;
function _create(super) {
function F () {}
F.prototype = super.prototype;
return new F ()
}
}
ES6继承
一个类可以去继承其他类里面的东西,这里定义一个叫Person的类,然后在constructor里面添加两个参数:name和birthday;
下面再添加一个自定义的方法intro,这个方法就是简单地返回this.name和this.birthday;class Person{
constructor(name,birthday){
this.name = name;
this.birthday= birthday;
}
intro(){
return '${this.name},${this.birthday}';
}
}
然后再定一个Chef类,使用extends去继承Person这个类,如果这个类里面有constructor方法,就要在constructor方法里面使用super,它可以去调用父类里面的东西 ```javascript class Chef extends Person{ constructor(name,birthday){ super(name,birthday); } }
let zhangsan = new Chef(‘zhangsan’,’1988-04-01’); console.log(zhangsan.intro()); //zhangsan,1988-04-01 ``` 因为Chef这个类继承了Person类,所以在Person类里面定义的方法可以直接使用