烦恼一般都是想太多了。

0%

JS原型继承的深入理解

JS 的继承是通过原型来实现的。每个对象都有一个原型属性 __proto__ ,然后,我们可以也多种方法来构造对象。但这中间有一些细节很值得我们深入了解。

文前

首先我们需要理解和区别,对象的原型属性(__proto__属性,或者通过 Object.getPrototypeOf()来获取) 与 函数的 prototype(此属性只有函数才有。prototype 属性的 constructor 指向函数本身)。

我们可以把 __proto__ 称为对象的原型,而把 prototype 称为函数的原型。

构造函数

一般来说,构造函数的首字母会大写,以此来与其他一般的函数进行区分。

我们定义一个构造函数:

function Person(first, last, age, gender, interests) {
this.name = {
first,
last
};
this.age = age;
this.gender = gender;
this.interests = interests;
};

函数,也是一个对象,其是一个 Function 的实例:

console.log(typeof Person);

// "function"。

函数,也有一个原型,我们这里并没有对他的原型做什么操作,所以其是默认的原生代码:

Object.getPrototypeOf(Person)

//ƒ () { [native code] }

可以看出,其原型是一个用原生代码编写的函数。 与 Object 的原型显示一样。

我们可以调用 Person.valueOf() 这样的函数,正是因为这是从 Object 原型继承的。

每一个函数对象,都有一个 prototype 属性(同时只有函数对象才有)。

因为:prototype 是定义在 Fuction 对象下的属性。

构造函数的 prototype 属性的构造方法(constructor),指向函数本身。

Person === Person.prototype.constructor。

我们可以进行验证:

Person.prototype

//{constructor: ƒ}
// constructor: ƒ Person(first, last, age, gender,interests)
//__proto__: Object

Person === Person.prototype.constructor
// true

构造对象

我们可以用 new 关键词来建立一个对象。

当我们输入类似var person1=new Person(…)来构造对象时,JavaScript实际上参考的是Person.prototype指向的对象来生成person1。

其基本流程是:

  1. 建立一个空对象。
  2. 将构造函数的执行环境绑定到此对象。(this 绑定,相当于调用 call(), apply())这样。
  3. 执行构造函数。
p1 = new Person();

我们可以更详细的看一下 p1 的内容:

Person {name: {…}, age: undefined, gender: undefined, interests: undefined}
age: undefined
gender: undefined
interests: undefined
name: {first: undefined, last: undefined}
__proto__:
constructor: ƒ Person(first, last, age, gender, interests)
__proto__: Object

p1 对象的原型,实际上指向的是构造函数的 prototype 属性:

Object.getPrototypeOf(p1) === Person.prototype

// true

Object.create()

我们可以把一个对象作为原型来建立对象,而不使用构造函数:

p2 = Object.create(p1);

我们可以验证, p2 的原型就是 p1:

Object.getPrototypeOf(p2) === p1

//true

我们也可以看到 p2, p1 是不同的:

p2
//Person {}__proto__: Personage: undefinedgender: undefinedinterests: undefinedname: {first: undefined, last: undefined}
// __proto__: Object


p1
//Person {name: {…}, age: undefined, gender: undefined, interests: undefined}
// age: undefined
// gender: undefined
// interests: undefined
// name: {first: undefined, last: undefined}
// __proto__: Object

p2 本身没有任何属性,只有一个 _proto_ 属性 指明其原型。其实就是指向 p1 的意思。

我们改变 p1 的值, p2 也会变化:

p1.age = 20;
p2.age

//20

class

ECMAScript6 引入了一套新的关键字用来实现 class。使用基于类语言的开发人员会对这些结构感到熟悉,但它们是不同的。JavaScript 仍然基于原型。这些新的关键字包括 class, constructor,static,extends 和 super。

"use strict";

class Polygon {
constructor(height, width) {
this.height = height;
this.width = width;
}
}

class Square extends Polygon {
constructor(sideLength) {
super(sideLength, sideLength);
}
get area() {
return this.height * this.width;
}
set sideLength(newLength) {
this.height = newLength;
this.width = newLength;
}
}

var square = new Square(2);