JS原型链继承

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JS原型链继承相关的知识,希望对你有一定的参考价值。

function Parent() 
this.name = red;
this.eat = function ()
console.log(走这里了吗)


Parent.prototype.start = function ()
console.log(this.name)

function Children()

Children的原型对象=Parent的原型对象

缺点: 实例对象p指向Parent; 实例对象p不能调用构造函数Parent的方法和属性,只能调用Parent的原型对象的方法和属性

//仅继承了Parent原型对象上的方法和属性
Children.prototype = Parent.prototype
let p = new Children();
console.log(p.name)//undefined
console.log(p.eat)//undefined
console.log(p.start)
//ƒ ()
// console.log(this.name);
//
console.log(p.constructor)
//ƒ Parent()
// this.name = red;
// this.eat = function ()
// console.log(走这里了吗);
// ;

Children.prototype = new Parent()

缺点: 实例对象p指向Parent

Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
let p = new Children();
console.log(p)//Children
console.log(p.name)//red
console.log(p.start)
//ƒ ()
// console.log(this.name);
//
console.log(p.eat)
// ƒ ()
// console.log(走这里了吗);
//
console.log(p.constructor)
// ƒ Parent()
// this.name = red;
// this.eat = function ()
// console.log(走这里了吗);
// ;
//

Children.prototype = new Parent()

Children.prototype.constructor = Children;

Children.prototype = new Parent()//继承了Parent的原型对象prototype的方法和属性以及constructor
Children.prototype.constructor = Children;
let p = new Children();
console.log(p.constructor);
// ƒ Children()

缺点

  1. 如果父构造函数中含有引用类型的属性,当某个实例改变了该引用类型的属性,则所有实例共享该实例(基本数据类型不会)
  2. 创建Children实例无法传参
function Parent() 
this.name = red;
this.arr = [1, 2, 3];
this.eat = function ()
console.log(走这里了吗)


Parent.prototype.start = function ()
console.log(this.name)

function Children()

Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children()
let p2 = new Children()
console.log(p1.arr)
p1.name = blue;
p1.arr.pop();
console.log(p1.name)//blue
console.log(p2.name)//red
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[2,3]

解决缺点一(构造函数继承)

某实例改变父构造函数中引用类型属性的值,所有实例共享修改后的引用类型的属性值

function Parent() 
this.arr = [1, 2, 3];

Parent.prototype.start = function ()

function Children()
Parent.apply(this)
//相当于执行了 this.arr = [1, 2, 3];

let p1 = new Children()
let p2 = new Children()
p1.arr.pop()
console.log(p1.arr)//[2,3]
console.log(p2.arr)//[1,2,3]

解决缺点二(构造函数继承)

生成实例时不能传参的问题

function Parent(color,name) 
this.color = color;
this.name = name;
this.arr = [1, 2, 3];
this.eat = function ()
console.log(走这里了吗)


Parent.prototype.start = function ()
// console.log(this.name,prototype)

function Children()
console.log(arguments,arguments)
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
Parent.call(this,...arguments)

let p1 = new Children()
let p2 = new Children(red,zhangsan)
console.log(p2.color)//red
console.log(p2.name)//zhangsan
console.log(p1.eat===p2.eat)//false

再次出现的问题

我们每次生成实例的时候都会重新生成构造函数的属性和方法

function Children() 
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
Parent.call(this,...arguments)

解决重新生成实例时生成构造函数的属性和方法(组合继承:原型链继承+构造函数继承)

  • 原型链继承:
  1. 实例改变引用类型的属性,所有实例共享
  2. 不能传参。
  • 构造函数继承:
  1. 解决了以上原型链的两个问题
  2. 但是又出现了新的问题,每次生成实例都会重新生成一份构造函数的属性和方法
function Parent(color,name) 
this.color = color;
this.name = name;
this.arr = [1, 2, 3];
this.eat = function ()
console.log(走这里了吗)


Parent.prototype.start = function ()
console.log(this.name,prototype)

function Children()
console.log(arguments,arguments)
//call传参为多个数值
//apply传值为数组
// Parent.apply(this,arguments)
// Parent.call(this,...arguments)
// Parent.apply(this,Array.prototype.slice.call(arguments, 1))
Parent.apply(this,[].slice.call(arguments, 1))

Children.prototype = new Parent();
Children.prototype.constructor = Children
let p1 = new Children(1,red,zhangsan)
let p2 = new Children(2,red,zhangsan)
console.log(p1.eat())
console.log(p2.eat())
console.log(p1.start===p2.start) //true

解决了三个痛点:

  1. 不可传参数
  2. 多占内存
  3. 改变引用类型属性,所有实例共享

寄生组合继承(再次出现问题,构造函数调用两次)

1. Parent.call(this,...arguments)
...
2.Children.prototype = new Parent();

以上是关于JS原型链继承的主要内容,如果未能解决你的问题,请参考以下文章

js继承之原型链继承

JS高级——原型链

原型链继承

js继承之原型继承

理解js中是原型链? 如何实现继承?

“工厂构造原型” 设计模式