We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Javascript的继承和传统的OO语言不一样,有一些特别的地方需要我们去注意。文章作为阅读红皮书(JS高程)的笔记,记录Javascript语言中的继承方式。
function SuperType() { this.property = true; } SuperType.prototype.getSuperValue = function() { return this.property; } function SubType() { this.subproperty = false; } // 继承 SubType.prototype = new SuperType(); SubType.prototype.getSubValue = function() { return this.subproperty; } const instance = new SubType(); instance.getSuperValue() // 输出SuperType中的true
原型链继承有它的缺点,就是包含引用类型值的原型属性会被所有实例共享,如下面这个例子
function SuperType() { this.colors = ['red', 'blue', 'green']; } function SubType() { } SubType.prototype = new SuperType(); const instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors); // "red, blue, green, black"; const instance2 = new SubType(); alert(instance2.colors); // "red, blue, green, black";
这个例子中的colors就是一个会被所有实例共享的对象。
原型继承的另一个缺点是在创建子类的实例时,不能向超类的构造函数传递参数。
function SuperType() { this.colors = ['red', 'blue', 'green']; } function SubType() { // 继承 SuperType.call(this); } const instance1 = new SubType(); instance1.colors.push('black'); alert(instance1.colors); // "red, blue, green, black"; const instance2 = new SubType(); alert(instance2.colors); // "red, blue, green";
通过SuperType.call(this)在SubType的对象上执行SuperType函数中定义的所有对象初始化代码。
并且借用构造函数还可以传递参数
function SuperType(name) { this.name = name; } function SubType() { // 继承 SuperType.call(this, 'Michael'); this.age = 25; } const instance = new SubType(); alert(instance.name); // 'Michael' alert(instance.age); // 25
但借用改造函数继承也有它的缺点,即无法避免构造函数模式存在的函数复用的问题,因为所有的方法都在构造函数中定义。
组合继承将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。
思路是使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。
function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age){ // 继承属性 SuperType.call(this, name); this.age = age; } // 继承方法 SubType.prototype = new SuperType(); SubType.prototype.sayAge = function() { alert(this.age); } const instance1 = new SubType('Michael', 25); instance1.colors.push('black'); alert(instance1.colors); // "red, blue, green, black" instance1.sayName(); // "Michael" instance1.sayAge(); // 25 const instance2 = new SubType('John', 27); alert(instance2.colors); // "red, blue, green" instance2.sayName(); // "John" instance2.sayAge(); // 27
组合继承解决了原型链与借用构造函数的缺陷,虽然它也有一定的问题,但它还是Javascript中最常用的继承模式。
原型式继承的思想是基于已有的对象创建新的对象,并添加自己需要的其他属性,而不必创建自定义类型。
function object(o) { function F(){}; F.prototype = o; return new F(); } // 即对传入的对象执行了一次浅复制,ES6添加了Object.create()方法来规范这中继承方式 const person = { name: 'Michael', friends: ["aa", "bb"] } const anotherPerson = Object.create(person, { name: { value: 'John' } }); alert(anotherPerson.name); // "John"
这种继承方式的所有实例也都会共享引用属性的值。
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象。
function createAnother(original) { const clone = new Object(original); // 这里可以换成其他自定义的生成对象的方法,如果是浅拷贝,则同样会共享引用类型的对象 clone.sayHi = function() { alert("Hi"); }; return clone; } const person = { name: 'Michael', friends: ["aa", "bb"] }; const anotherPerson = createAnother(person); anotherPerson.sayHi(); // "Hi"
前面所述的组合继承的最大问题就是会调用两次超类型构造函数,一次是创建子类原型的时候,另一次是在子类型构造函数内部。其结果是子类型的实例属性屏蔽了它的原型属性,原型上依然存在着相应的属性。
寄生组合式继承的基本思路是使用寄生式继承来继承超类的原型,然后再将结果指定给子类型的原型
function inheritPrototype(subType, superType) { // 创建超类的一个副本 const prototype = new Object(superType.prototype); // 为创建的副本添加constructor属性,弥补因重写原型而失去的默认的constructor属性 prototype.constructor = subType; // 将新创建的对象赋值给子类型的原型 subType.prototype = prototype; } function SuperType(name) { this.name = name; this.colors = ['red', 'blue', 'green']; } SuperType.prototype.sayName = function() { alert(this.name); } function SubType(name, age){ // 继承属性 SuperType.call(this, name); this.age = age; } inheritPrototype(SubType, superType); SubType.prototype.sayAge = function () { alert(this.age); };
The text was updated successfully, but these errors were encountered:
No branches or pull requests
1.原型链继承
原型链继承有它的缺点,就是包含引用类型值的原型属性会被所有实例共享,如下面这个例子
这个例子中的colors就是一个会被所有实例共享的对象。
原型继承的另一个缺点是在创建子类的实例时,不能向超类的构造函数传递参数。
2.借用构造函数(经典继承)
通过SuperType.call(this)在SubType的对象上执行SuperType函数中定义的所有对象初始化代码。
并且借用构造函数还可以传递参数
但借用改造函数继承也有它的缺点,即无法避免构造函数模式存在的函数复用的问题,因为所有的方法都在构造函数中定义。
3.组合继承(伪经典继承)
组合继承将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。
思路是使用原型链实现对原型属性和方法的继承,而通过构造函数来实现对实例属性的继承。
组合继承解决了原型链与借用构造函数的缺陷,虽然它也有一定的问题,但它还是Javascript中最常用的继承模式。
4.原型式继承
原型式继承的思想是基于已有的对象创建新的对象,并添加自己需要的其他属性,而不必创建自定义类型。
这种继承方式的所有实例也都会共享引用属性的值。
5.寄生式继承
寄生式继承的思路与寄生构造函数和工厂模式类似,即创建一个仅用于封装过程的函数,该函数在内部以某种方式来增强对象,最后返回这个对象。
6.寄生组合式继承
前面所述的组合继承的最大问题就是会调用两次超类型构造函数,一次是创建子类原型的时候,另一次是在子类型构造函数内部。其结果是子类型的实例属性屏蔽了它的原型属性,原型上依然存在着相应的属性。
寄生组合式继承的基本思路是使用寄生式继承来继承超类的原型,然后再将结果指定给子类型的原型
The text was updated successfully, but these errors were encountered: