Comments (11)
- 首先借用构造函数继承,指的是继承父类的属性,同时还能传递参数,如
function SuperType(name){
this.name = name
// ...
}
function SubType(){
// 继承了SuperType,同时还可以传递参数
SuperType.call(this)
}
优点:实现属性的继承
缺点:不能继承父类的方法
- 组合继承(伪经典继承)指的是将原型链和构造函数组合到一块,如
function SubType(age) {
// 继承属性
SuperType.call(this, '组合')
this.age = age
}
// 继承方法
SubType.prototype = new SuperType()
SubType.prototype.constructor = SubType // 修正constructor指向
SubType.prototype.sayAge = function(){
alert(this.age)
}
优点:可以实现属性、以及方法的继承
缺点: 调用了2次父类的构造函数,一次是SuperType.call(),还有一次是new SuperType()
from step-by-step.
借用构造函数的优缺点
代码实现:
function Person(name) {
this.name = name
this.className = 'person'
}
Person.prototype.getName = function () {
console.log(this.name)
}
function Man(name) {
Person.apply(this, arguments)
}
优点: 只继承了父类的属性
缺点: 没有继承方法
组合继承(伪经典继承)的优缺点
这里组合是指同事继承之类构造函数和原型中的属性
function Person(name) {
this.name = name
this.className = 'person'
}
Person.prototype.getName = function () {
console.log(this.name)
}
function Man(name) {
Person.apply(this, arguments)
}
// 注意此处
Man.prototype = Object.create(Person.prototype);
Man.prototype.constructor = Man
var man1 = new Man ("Davin")
这里用到了Object.create()方法,该方法会对传入obj对象进行前拷贝。和上面的主要区别就是:将父类的原型复制给了之类原型。
- 构造函数中继承分类属性/方法,并初始化父类
- 子类原型和父类原型建立联系
优点:结合了原型继承和构造函数继承
缺点:无论什么情况下,会调用两次构造函数Person.call(), new Person()
from step-by-step.
构造函数和组合继承
function Animal () {
this.type =['origin']
}
Animal.prototype.tellOrigin = function () {
console.log(this.type)
}
function Dog () {
this.ownType = 'dog'
Animal.call(this)
}
const dog = new Dog() // new 使 this 指向对象
const dog1 = new Dog()
dog1.type.push('hello')
console.log(dog.type) // ['origin']
console.log(dog1.type) // [ 'origin', 'hello']
dog.tellOrigin() // 会报错
如上面代码所示:
- 优点 父类的属性能被子类继承,切不会被所有子类共用
- 缺点 父类的原型对象方法不能被使用
组合继承就是,原型继承和构造函数继承的组合
function Animal () {
this.type =['origin']
}
Animal.prototype.tellOrigin = function () {
console.log(this.type)
}
function Dog () {
this.ownType = 'dog'
Animal.call(this)
}
Dog.prototype = new Animal()
const dog = new Dog()
const dog1 = new Dog()
dog1.type.push('hello')
console.log(dog.type) // ['origin']
console.log(dog1.type) // [ 'origin', 'hello']
dog.tellOrigin() // ['origin']
完美解决了,原型继承和构造函数的缺点
from step-by-step.
借用构造函数
借用构造函数的技术,其基本**为:
在子类型的构造函数中调用超类型构造函数。
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
function SubType(name) {
SuperType.call(this, name);
}
let instance1 = new SubType('Yvette');
instance1.colors.push('yellow');
console.log(instance1.colors);//['pink', 'blue', 'green', yellow]
let instance2 = new SubType('Jack');
console.log(instance2.colors); //['pink', 'blue', 'green']
优点:
- 可以向超类传递参数
- 解决了原型中包含引用类型值被所有实例共享的问题
缺点:
- 方法都在构造函数中定义,函数复用无从谈起,另外超类型原型中定义的方法对于子类型而言都是不可见的。
组合继承(原型链 + 借用构造函数)
组合继承指的是将原型链和借用构造函数技术组合到一块,从而发挥二者之长的一种继承模式。基本思路:
使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承,既通过在原型上定义方法来实现了函数复用,又保证了每个实例都有自己的属性。
function SuperType(name) {
this.name = name;
this.colors = ['pink', 'blue', 'green'];
}
SuperType.prototype.sayName = function () {
console.log(this.name);
}
function SuberType(name, age) {
SuperType.call(this, name);
this.age = age;
}
SuberType.prototype = new SuperType();
SuberType.prototype.constructor = SuberType;
SuberType.prototype.sayAge = function () {
console.log(this.age);
}
let instance1 = new SuberType('Yvette', 20);
instance1.colors.push('yellow');
console.log(instance1.colors); //[ 'pink', 'blue', 'green', 'yellow' ]
instance1.sayName(); //Yvette
let instance2 = new SuberType('Jack', 22);
console.log(instance2.colors); //[ 'pink', 'blue', 'green' ]
instance2.sayName();//Jack
优点:
- 可以向超类传递参数
- 每个实例都有自己的属性
- 实现了函数复用
from step-by-step.
借用构造函数的基本**是在子类型构造函数的内部调用超类型构造函数。
借用构造函数的优点:可以在子类型构造函数中向超类型构造函数传递参数。
function SuperType(name){
This.name = name;
}
Function SubType(){
//继承了SuperType,同时还传递了参数
SuperTYpe.call(this,’yay’);
//实例属性
this.age = 29;
}
Var instance = new SubType();
Console.log(instance.name); //yay
Console.log(instance.age); //29
借用构造函数的缺点:无法实现函数复用
组合继承:指的是将原型链和借用构造函数的技术组合到一块,从而发挥二者之长的一种继承模式。其背后的思路是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。
function SuperTYpe(name){
This.name = name;
This.color = [‘red’,’blue’,’green’];
}
SuperType.prototype.sayName = function(){
Console.log(this.name);
}
Function SubType(name,age){
SuperType.call(this,name);
This.age = age;
}
//继承方法
SubType.protype = new SuperType();
SubType.prototype.constructor = SubType;
SubType.prototype.sayAge = function(){
Console.log(this.age);
}
Var instance1 = new SubType(‘yay’,29);
Instance1.color.push(‘black’);
Console.log(instance1.color); //red,blue,green,black
Instance1.sayName(); //yay
Instance.sayAge(); //29
Var instance2 = new SubType(‘Greg’,27);
Console.log(instance.color); //red,blue,green
Instance2.sayName(); //Greg
Instance2.sayAge(); //27
组合继承的优点:可以实现函数复用;可以向超类传递参数;每个实例可以拥有自己的属性
from step-by-step.
借用构造函数继承
function Parent( name ) {
this.name = name;
}
function Child(name) {
Parent.call(this, name)
}
let child1 = new Child('zhangsan')
console.log(child1.name)
let child2 = new Child('lisi')
console.log(child2.name)
优缺点:
优点:避免了实例之间属性的共享,可以向构造函数传参;
缺点:方法都在构造函数中实现,每创建一个实例,都要调用一次方法,没有实现函数的复用。
组合继承
组合继承是原型链继承和构造函数继承相结合。
function Parent(name) {
this.name = name;
}
Parent.prototype.getName = function() {
console.log(this.name)
}
function Child(name) {
Parent.call(this, name)
}
Child.prototype = new Parent()
let child1 = new Child('zhangsan')
console.log(child1.getName())
let child2 = new Child('lisi')
console.log(child2.getName())
优缺点:
优点:具有构造函数继承的优点,同时可以实现函数的复用
缺点:调用了2次父类的构造函数,一次是Parent.call(),一次是new Parent()
from step-by-step.
借用构造函数
使用原型链继承的一个缺点就是如果原型是另一个类型的实例并且这个实例对象包含一个引用类型的值,那么通过这个实例创建的其他实例都会共享这个引用类型的值,在很多业务情况下可能并不是我们想要的。借用构造函数的本质就是在子类型的构造函数中调用超类型的构造函数,这样即使超类型中包含的有引用类型的属性值那么也可以让子类型的每一个实例对象获取一个副本,子类型的对象之间互不影响~
function SuperType(type) {
this.type = type;
this.friends = ['a', 'b'];
}
function SubType() {
SuperType.call(this, 'SubType');
}
let sub1 = new SubType();
let sub2 = new SubType();
sub1.friends.push('c');
console.log(sub1.friends); // ['a', 'b', 'c']
console.log(sub2.friends); // ['a', 'b']
优点
- 可以给父类的构造函数传递参数
- 可以解决引用类型的值带来的问题
缺点
- 没有利用原型链,无法继承超类型原型链上的方法和属性
组合式继承
将原型链继承和借用构造函数结合起来,使用原型链实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承。
优点
1.在原型上定义方法实现函数的复用
2.保证每个实例都有自己的属性
function SuperType(type) {
this.type = type;
this.friends = ['a', 'b'];
}
SuperType.prototype.getFriends = function() {
return this.friends;
}
function SubType() {
SuperType.call(this, 'SubType');
}
SubType.prototype = new SuperType();
let sub1 = new SubType();
let sub2 = new SubType();
sub1.friends.push('c');
console.log(sub1.getFriends()); // ['a', 'b', 'c']
console.log(sub2.getFriends()); // ['a', 'b']
from step-by-step.
借用构造函数继承?
function Super(name){
this.name = name
}
function Suber(name){
Super.call(this,name)
}
const sub1 = new Suber('单身狗');
const sub2 = new Suber('没女票');
缺点: 无法继承原型链上的属性和方法
优点: 可以向构造函数传参,避免了原型链继承时引用类型的属性被共享。
组合式继承
function Super(text){
this.text = text
}
Super.prototype.say=function(){
console.log(this.text)
}
function Suber(text){
Super.call(this,text)
}
Suber.prototype = new Super()
var sub1 = new Suber('2019/6/26 17:53 publish on github')
var sub2 = new Suber('2019/6/26 17:53 地铁可能已开始拥挤')
sub1.say()
sub2.say()
优点: 组合式继承 将原型链继承 与借用构造函数继承 结合 使用原型链继承 原型上的方法和属性 使用构造函数 继承实例上的属性。
缺点 : 调用两次构造函数 Super.call(), new Super()
from step-by-step.
1.借用构造函数
通过使用call方法,我们再未来将要新创建的SubType实例环境下调用了 SuperType构造函数,这样一来,就会在新的SubType对象上执行SuperType()函数中定义的所有对象初始化代码。这样,SubType的每个实例都会具有自己的colors属性的副本。
function SuperType(name){
this.name=name
this.colors=['white','red']
}
function SubType(){
//继承属性,传递参数
SuperType.call(this,'Jodie')
this.age=18
}
var instance1=new SubType()
instance1.colors.push('black')
console.log(instance1.name)
console.log(instance1.age)
console.log(instance1.colors)
var instance2=new SubType()
console.log(instance2.name)
console.log(instance2.age)
console.log(instance2.colors)
Jodie
18
[ 'white', 'red', 'black' ]
Jodie
18
[ 'white', 'red']
问题:
超类型的原型定义的方法对子类型而言是不可见的。
function SuperType(name){
this.name=name
this.colors=['white','red']
this.sayHi=function(){
console.log('123')
}//方法都在构造函数中定义
}
function SubType(){
//继承属性,传递参数
SuperType.call(this,'Jodie')
this.age=18
}
var instance1=new SubType()
instance1.colors.push('black')
console.log(instance1.name)
console.log(instance1.age)
console.log(instance1.colors)
instance1.sayHi()
2.组合继承
将原型链和借用构造函数的技术组合到一起,从而发挥二者所长的一种继承模式。
背后的思路就是使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过原型上定义方法实现函数复用,有能够保证每个实例都有自己的属性。
function SuperType(name){
this.name=name;
this.colors=["red","blue","green"]
}
SuperType.prototype.sayName=function(){
console.log(this.name)
}
function SubType(name,age){
//继承属性
SuperType.call(this,name)
this.age = age
}
//继承方法
SubType.prototype = new SuperType();
SubType.prototype.constructor=SubType
SubType.prototype.sayAge = function(){
console.log(this.age)
}
var instance1 = new SubType("Jodie","18")
instance1.colors.push("black")
console.log(instance1.colors)
instance1.sayName()
instance1.sayAge()
var instance2 = new SubType('Wen','5')
console.log(instance2.colors)
instance2.sayName()
instance2.sayAge()
[ 'red', 'blue', 'green', 'black' ]
Jodie
18
[ 'red', 'blue', 'green' ]
Wen
5
这是JavaScript中最常用的继承模式
from step-by-step.
1.借用构造函数
在解决原型中包含的引用类型所带来的问题的过程中,开发人员开始使用一种叫做构造函数的技术。这种技术的基本**相当简单,即在子类型函数的内部调用超类型构造型构造函数。
function SuperType(){
this.colors = ['red','blue','green'];
}
function SubType(){
//继承superType
SuperType.call(this)
}
var instancel = new SubType();
instancel.colors.push("blcak");
console.log(instancel.colors) // ["red","blue","green","blcak"]
var instance2 = new SubType();
console.log(instance2.colors) //["red", "blue", "green"]
借用构造函数的基本**就是利用call或apply把父类中通过this指定的属性和方法复制(借用)到子类创建的实例中,因为this对象是在运行时基于函数的执行环境绑定的。
优势:相对于原型链而言,借用构造函数有一个很大的优势,即可以在子类型构造函数中向超类型构造函数传参。因为属性是绑定带this上,所以调用时互不影响。
劣势:仅借用构造函数,将无法避免方法都在构造函数中定义,因此函数复用就无从谈起。
2.组合继承(又称 伪经典继承)
将原型链和借用构造函数的技术结合到一起,从而发挥二者之长的一种继承模式。
function SuperTypes(name){
this.name = name;
this.colors = ["red", "blue", "green"];
}
SuperTypes.prototype.sayName = function(){
console.log(this.name)
}
function SubTypes(name,age){
//继承属性
SuperTypes.call(this,name)
this.age = age
}
//继承方法
SubTypes.prototype = new SuperTypes()
SubTypes.prototype.constructor = SubTypes;
SubTypes.prototype.sayAge = function () {
console.log(this.age)
}
var instance3 = new SubTypes("Nicholas", 29);
instance3.sayAge(); //29
instance3.sayName(); //Nicholas
var instance4 = new SubTypes("Greg", 27);
优势:组合继承避免了原型链和借用构造函数的缺陷,融合了它们的优点,成为js中最常用的继承模式.
劣势:组合继承最大的问题是无论什么情况下,都会调用两次超类型的构造函数:一次在创建子类型原型的时候,另一次在子类型构造函数内部。输入子类型最终会包含超类型对象的全部实例属性,但我们不得不在调用子类型构造函数时重写这些属性。
from step-by-step.
借用构造函数(伪造对象或经典继承)
基本**:在子类型构造函数的内部调用超类型的构造函数
优点: 相比原型链而言,借用构造函数有一个很大的优势,就是子类型函数构造函数可以向超类型构造函数传递参数
缺点: 方法都在构造函数中定义,因此函数的复用性就无从谈起了
function Animal(speices){
this.speices = speices;
}
function Dog(){
Animal.call(this,'中华田园犬'); // dog拥有了animal中的name属性
}
var dog1 = new Dog();
var dog2 = new Dog();
console.log(dog1.speices); // 中华田园犬
组合继承(原型链+借用构造函数)
- 基本**: 原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承
- 优点: 在原型上定义方法是实现了函数复用,又能偶保证每个实例都有它自己的属性
function Animal(speices){
this.speices = speices;
this.skills = ["jump","climb","catch","run"]
}
Animal.prototype.getSpeices = function(){
console.log(this.speices)
}
function Dog(speices,color){
// 借用构造函数继承,继承父类的属性
Animal.call(this,speices);
this.color = color;
}
// 原型继承,继承父类的方法
Dog.prototype = new Animal();
Dog.prototype.getColors = function(){
console.log(this.colors);
}
var dog1 = new Dog('博美','white');
dog1.skills.push('acting');
console.log(dog.skills); // ["jump","climb","catch","run","acting"]
dog1.getSpeices(); // 博美
var dog2 = new Dog('柯基','brown');
console.log(dog2.skills); // ["jump","climb","catch","run"]
dog2.getSpeices(); // 柯基
组合继承融合借用构造函数(属性继承)和原型链继承(方法继承)的优点,使实例都有自己的属性,又能共享统一方法,成为最常用的继承方法
from step-by-step.
Related Issues (20)
- 实现 Promise.race 方法 HOT 13
- JSONP原理及简单实现 HOT 17
- 实现一个数组去重的方法 HOT 24
- 清除浮动的方法有哪些? HOT 17
- 编写一个通用的柯里化函数currying HOT 14
- 原型链继承的优缺点是什么?使用原型链继承实现 Dog 继承 Animal HOT 19
- 原型式继承的基本**是什么?有什么优缺点? HOT 13
- 寄生式继承的基本思路是什么?有什么优缺点? HOT 7
- 寄生组合式继承的基本**是什么?有哪些优缺点? HOT 11
- 实现一个 JSON.stringify HOT 9
- 实现一个 JSON.parse HOT 9
- 实现一个观察者模式 HOT 10
- 使用CSS让一个元素水平垂直居中 HOT 11
- ES6模块和CommonJS模块有哪些差异? HOT 8
- 如何使用Proxy实现简单MVVM HOT 2
- 以下代码的输出的结果为: HOT 7
- 列举常见的JS和CSS兼容性问题
- 介绍下 Set、Map、WeakSet 和 WeakMap 的区别? HOT 1
- Vue组件间是怎么进行参数传递的? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from step-by-step.