ThinkChat2.0新版上线,更智能更精彩,支持会话、画图、阅读、搜索等,送10W Token,即刻开启你的AI之旅 广告
ES5 继承有许多中方式,我们这里只说普通常用的继承方式 ## 原型链赋值继承 ```js function father(name){ this.name=name; } father.prototype.sayName=function(){ console.log(this.name); } function sub(age){ this.age=age; } sub.prototype=new father(); sub.prototype.sayAge=function(){ console.log(this.age); } ``` 上面就是典型的原型链赋值继承,但是这个继承是有缺点的,在继承时需要 `new` 关键字进行处理。 ## 构造函数继承 ```js function father(name){ this.name=name; this.age=22; } father.prototype.sayName=function(){ console.log(this.name); } function sub(){ father.apply(this,arguments) } var s=new sub("a") > s > sub {name: "a", age: 22} age: 22 name: "a" __proto__: constructor: ƒ sub() __proto__: Object ``` 构造函数继承最后在输出中会发现并没有 父级的方法 ,但是可以将数据传到父级,与原型链继承互补,所以衍生出组合继承的方式 ## 组合继承 ```js function Father(name) { this.name = name; this.className = "Father" } Father.prototype.sayName = function () { console.log(this.name) } function Sub(name) { Father.apply(this, arguments) } //继承原型 Sub.prototype = new Father(); var s=new Sub("张三",12); ``` 不仅会继承构造函数中的属性,也会复制父类原型链中的属性 但是在 `Sub.prototype = new Father();` 之后 Sub 的原型变成这样的了 ```js > Sub.prototype > {name: undefined, className: "person"} ``` 也就是说Sub的原型中已经有了一个name属性,而之后创建 s 时传给构造的函数的name则是通过this重新定义了一个name属性,相当于只是覆盖掉了原型的name属性(原型中的name依然还在),这样很不优雅。 ## 寄生组合继承 ```js function Father(name) { this.name = name; this.className = "Father" } Father.prototype.sayName = function () { console.log(this.name) } function Man(name,age) { this.age=age; Father.call(this, name) } // 注意此处 Man.prototype=Object.create(Father.prototype) Man.prototype.sayAge=function(){ console.log(this.age) } ``` 这里用到了 `Object.creat(obj)` 方法,该方法会对传入的obj对象进行浅拷贝。和上面组合继承的主要区别就是:将父类的原型复制给了子类原型。这种做法很清晰: 1. 构造函数中继承父类属性/方法,并初始化父类。 2. 子类原型和父类原型建立联系。 还有一个问题,就是constructor属性,我们来看一下: ```js > Father.prototype.constructor < Father(name){ this.name=name; this.className="Father" } > Sub.prototype.constructor < Father(name){ this.name=name; this.className="Father" } ``` constructor是类的构造函数,我们发现,Father和Sub实例的constructor指向都是Father,当然,这并不会改变instanceof的结果,但是对于需要用到construcor的场景,就会有问题。所以一般我们会加上这么一句: ```js Sub.prototype.constructor = Sub ```