首页 > 技术文章 > JavaScript原型、构造函数、继承、类

starlog 2021-04-13 22:01 原文

一、理解原型:

 

在JavaScript中,可通过原型实现继承。

原型的概念很简单。每个对象都含有原型的引用,当查找属性时,若对象本身不具有该属性,则会查找原型上是否有该属性。可以假想一下,你正在和一组人共同玩一个游戏,游戏规则为:主持人提问,如果你知道答案,则可直接回答;如果你不知道答案,则可以询问你的下一个人。就是那么简单。

在JavaScript中,对象的原型属性是内置属性(使用标记[[prototype]]),无法直接访问。相反,内置的方法Object.setPrototypeOf需要传入两个对象作为参数,并将第二个对象设置为第一个对象的原型。

每个对象都可以有一个原型,每个对象的原型也可以拥有一个原型,以此类推,形成一个原型链。查找特定属性将会被委托在整个原型链上,只有当没有更多的原型可以进行查找时,才会停止查找。

 

二、对象构造器与原型:

 

通过操作符new,应用于构造函数之前,触发创建一个新对象分配。

每个函数都有一个原型对象,该原型对象将被自动设置为通过该函数创建对象的原型。

当函数创建完成之后, 立即就获得了一个原型对象, 我们可以对该原型对象进行扩展。

· 每一个函数都具有一个原型对象。
· 每一个函数的原型都具有一个constructor属性,该属性指向函数本身。
· constructor对象的原型设置为新创建的对象的原型。

我们创建的每一个函数都具有一个新的原型对象。

最初的原型对象只有一个属性,即constructor属性。该属性指向函数本身。

当我们将函数作为构造器进行调用时,新构造出来的对象的原型被设置为构造函数的原型的引用。

 

三、实现继承:

 

function Person() {}
Person.prototype.dance = function() {};

function Ninja() {}
Ninja.prototype = new Person();
Object.defineProperty(Ninja.prototype, "constructor", {
  enumerable: false,
  value: Ninja,
  writable: true //定义一个新的不可枚举的constructor属性,属性值为Ninja
});

 

寄生组合式继承:
function Parent(name, actions) {
  this.name = name;
  this.actions = actions;
}

Parent.prototype.eat = function () {
  console.log(`${this.name} - eat`);
}

function Child(id) {
  Parent.apply(this, Array.from(arguments).slice(1));
  this.id = id;
}

let TempFunction = function () {}
TempFunction.prototype = Parent.prototype;
Child.prototype = new TempFunction();
Child.prototype.constructor = Child;

 

四、类:

 

使用类实现继承:

class Person {
  constructor(name) {
    this.name = name;
  } 
  dance() {
    return true;
  }
} 
  
class Ninja extends Person { //使用关键字extends实现继承
  constructor(name, weapon) {
    super(name); //使用关键字super调用基类构造函数
    this.weapon = weapon;
  } 
  wieldWeapon() {
    return true;
  }
}

 

五、原型链查找顺序:

 

1.实例对象自身
2.实例对象的构造函数
3.实例对象的原型,也就是构造函数的原型对象
4.实例对象的原型的原型,也就是构造函数的原型对象的原型

 

六、小结:

 

·JavaScript对象是属性名与属性值的集合。

·JavaScript使用原型。

·每个对象上都具有原型的引用, 搜索指定的属性时, 如果对象本身不存在该属性, 则可以代理到原型上进行搜索。 对象的原型也可以具有原型, 以此类推, 形成原型链。

·可以通过Object.setPrototypeOf方法定义对象的原型。

·原型与构造函数密切相关。 每个函数都具有prototype属性, 该函数创建的对象的原型, 就是函数的原型。

·函数原型对象具有constructor属性, 该属性指向函数本身。 该函数创建的全部对象均访问该属性, constructor属性还可用于判断对象是否是由指定的函数创建的。

·在JavaScript中, 几乎所有的内容在运行时都会发生变化, 包括对象的原型和函数的原型。

·如果我们希望Ninja构造函数创建的实例都可以“继承”( 更准确地说, 可以访问) Person构造函数的属性, 那么, 将Ninja构造函数的原型设置为Person类的实例。

·在JavaScript中, 原型具有属性( 如configurable、 enumerable、writable) 。 这些属性可通过内置的Object.defineProperty方法进行定义。

·JavaScript ES6引入关键字class, 使得我们可以更方便地实现模拟类。 在底层仍然是使用原型实现的。

·使用extends可以更优雅地实现继承。

 

推荐阅读