沈阳大型网站设计公司,好的室内设计网站推荐,如何做网络营销推广工作,网站开发模块查相似本文将从最简单的例子开始#xff0c;从零讲解在 JavaScript 中如何实现继承。 小例子 现在有个需求#xff0c;需要实现 Cat 继承 Animal #xff0c;构造函数如下#xff1a; function Animal(name){this.name name
}function Cat(name){this.name name
}
复制代码注从零讲解在 JavaScript 中如何实现继承。 小例子 现在有个需求需要实现 Cat 继承 Animal 构造函数如下 function Animal(name){this.name name
}function Cat(name){this.name name
}
复制代码注如对继承相关的 prototype、constructor、__proto__、new 等内容不太熟悉可以先查看这篇文章理性分析 JavaScript 中的原型 继承 在实现这个需求之前我们先谈谈继承的意义。继承本质上为了提高代码的复用性。 对于 JavaScript 来说继承有两个要点 复用父构造函数中的代码复用父原型中的代码下面的内容将围绕这两个要点展开。 第一版代码 复用父构造函数中的代码我们可以考虑调用父构造函数并将 this 绑定到子构造函数。 复用父原型中的代码我们只需改变原型链即可。将子构造函数的原型对象的 __proto__ 属性指向父构造函数的原型对象。 第一版代码如下 function Animal(name){this.name name
}function Cat(name){Animal.call(this,name)
}Cat.prototype.__proto__ Animal.prototype
复制代码检验一下是否继承成功我们在 Animal 的原型对象上添加 eat 函数。使用 Cat 构造函数生成一个名为 Tom 的实例对象 cat 。代码如下 function Animal(name){this.name name
}function Cat(name){Animal.call(this,name)
}Cat.prototype.__proto__ Animal.prototype// 添加 eat 函数
Animal.prototype.eat function(){console.log(eat)
}var cat new Cat(Tom)
// 查看 name 属性是否成功挂载到 cat 对象上
console.log(cat.name) // Tom
// 查看是否能访问到 eat 函数
cat.eat() // eat
// 查看 Animal.prototype 是否位于原型链上
console.log(cat instanceof Animal) // true
// 查看 Cat.prototype 是否位于原型链上
console.log(cat instanceof Cat) //true
复制代码经检验成功复用父构造函数中的代码并复用父原型对象中的代码原型链正常。 图示 弊端 __proto__ 属性虽然可以很方便地改变原型链但是 __proto__ 直到 ES6 才添加到规范中存在兼容性问题并且直接使用 __proto__ 来改变原型链非常消耗性能。所以 __proto__ 属性来实现继承并不可取。 第二版代码 针对 __proto__ 属性的弊端我们考虑使用 new 操作符来替代直接使用 __proto__ 属性来改变原型链。 我们知道实例对象中的 __proto__ 属性指向构造函数的 prototype 属性的。这样我们 Animal 的实例对象赋值给 Cat.prototype 。不就也实现了Cat.prototype.__proto__ Animal.prototype 语句的功能了吗 代码如下 function Animal(name){this.name name
}function Cat(name){Animal.call(this,name)
}Cat.prototype new Animal()
Cat.prototype.constructor Cat
复制代码使用这套方案有个问题就是在将实例对象赋值给 Cat.prototype 的时候将 Cat.prototype 原有的 constructor 属性覆盖了。实例对象的 constructor 属性向上查询得到的是构造函数 Animal 。所以我们需要矫正一下 Cat.prototype 的 constructor 属性将其设置为构造函数 Cat 。 图示 优点 兼容性比较好并且实现较为简单。 弊端 使用 new 操作符带来的弊端是执行 new 操作符的时候会执行一次构造函数将构造函数中的属性绑定到这个实例对象。这样就多执行了一次构造函数将原本属于 Animal 实例对象的属性混到 prototype 中了。 第三版代码 考虑到第二版的弊端我们使用一个空构造函数来作为中介函数这样就不会将构造函数中的属性混到 prototype 中并且减少了多执行一次构造函数带来的性能损耗。 代码如下 function Animal(name){this.name name
}function Cat(name){Animal.call(this,name)
}
function Func(){}
Func.prototype Animal.prototypeCat.prototype new Func()
Cat.prototype.constructor Cat
复制代码图示 ES6 使用 ES6 就方便多了。可以使用 extends 关键字实现继承 复用父原型中的代码。使用 super 关键字来复用父构造函数中的代码。 代码如下 class Animal {constructor(name){this.name name}eat(){console.log(eat)}
}
class Cat extends Animal{constructor(name){super(name)}
}let cat new Cat(Tom)
console.log(cat.name) // Tom
cat.eat() // eat
复制代码相关知识点 理性分析 JavaScript 中的 this理性分析 JavaScript 中的原型参考书籍 《JavaScript高级程序设计第3版》《Java核心技术 卷Ⅰ第9版》