webVueBlog/Leetcode

【深入理解JS核心技术】2. 什么是原型链?

webVueBlog opened this issue · 2 comments

原型链是用于在现有对象的基础上构建新类型的对象。它类似于基于类的语言中的继承。

对象实例的原型可以通过 Obeject.getPrototypeOf(object) 或 __proto__ 属性获得,而构造函数的原型可通过 Object.prototype 获得。

构造函数,原型,实例的关系:

每个构造函数都有一个原型对象,原型有一个属性指回构造函数,而实例有一个内部指针指向原型。

原型链的基本**:(如果原型是另一个类型的实例?)原型当成实例。

意味着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
};

function SubType() {
 this.subproperty = false;
}

// 继承SuperType
SubType.prototype = new SuperType();

SubType.prototype.getSubValue = function() {
 return this.subproperty;
};

let instance = new SubType();
console.log(instance.getSuperValue()); // true
  1. 默认原型

默认情况下,所有引用类型都继承自Object,这也是通过原型链实现的。任何函数的默认原型都是一个Object的实例,这意味着这个实例有一个内部指针指向Object.prototype。

  1. 原型与继承关系

原型与实例的关系可以通过两种方式来确定。第一种方式是使用instanceof操作符,如果一个实例的原型链中出现过相应的构造函数,则instanceof返回true。

确定关系的第二种方式是使用 isPrototypeOf() 方法。原型链中的每个原型都可以调用这个方法。

// 只要原型链中包含这个原型,这个方法就返回true
console.log(Object.prototype.isPrototypeOf(instance)); // true
  1. 关于方法

子类有时候需要覆盖父类的方法,或者增加父类没有的方法。这些方法必须在原型赋值之后再添加到原型上。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
}

function SubType() {
 this.subproperty = false;
}

// 继承SuperType
SubType.prototype = new SuperType();

// 新方法
SubType.prototype.getSubValue = function() {
 return this.subproperty;
};

// 覆盖已有的方法
SubType.prototype.getSuperValue = function() {
 return false;
};

let instance = new SubType();
console.log(instance.getSuperValue()); // false

重点:如果以对象字面量方式创建原型方法会破坏之前的原型链,因为这相当于重写了原型链。

function SuperType() {
 this.property = true;
}

SuperType.prototype.getSuperValue = function() {
 return this.property;
};

function SubType() {
 this.subproperty = false;
};

// 继承SuperType
SubType.prototype = new SuperType();

// 通过对象字面量添加新方法,这会导致上一行无效
SubType.prototype = {
 getSubValue() {
  return this.subproperty;
 },
 someOtherMethod() {
  return false;
 }
};

let instance = new SubType();
console.log(instance.getSuperValue()); // 出错
  1. 原型链的问题

原型中包含的引用值会在所有实例间共享,这也是为什么属性通常会在构造函数中定义而不会在原型上的原因。

在使用原型实现继承时,原型实际上变成了另一个类型的实例。(原先的实例属性变成了原型属性)

function SuperType() {
 this.colors = ["red", "blue", "green"];
}

function SubType() { }

// 继承SuperType
SubType.prototype = new SuperType();

let instance1 = new SubType();
instance1.colors.push('black');
console.log(instance1.colors); // "red,blue,green,black"

let instance2 = new SubType();
console.log(instance2.colors); // "red,blue,green,black"

原型链的第二个问题:子类型在实例化时不能给父类型的构造函数传参。

未完结!更多内容尽情期待下一节~

【深入理解JS核心技术】欢迎各位观众老爷,求点赞,求关注,求转发~

“对象实例的原型可以通过 Obeject.getPrototypeOf(object) 或 proto 属性获得”,这里应该是 __ proto __ 属性吧。两边双下划线加粗了

“对象实例的原型可以通过 Obeject.getPrototypeOf(object) 或 proto 属性获得”,这里应该是 __ proto __ 属性吧。两边双下划线加粗了

嗯嗯🤔 ,md语法显示问题,已更新!!!