All articles

A Beginner’s Guide to JavaScript’s Prototype

Apr 09, 2022

弄清楚原型链相等关系和原型、原型链存在的意义

前言

  • JS 内函数即对象,分为函数对象和普通对象,每个对象都有__proto__属性,但只有函数对象才有prototype属性。
  • Object、Function 都是 js 内置的函数, 类似的还有常用到的 Array、RegExp、Date、Boolean、Number、String。
  • 属性__proto__是一个对象,它有两个属性,constructor__proto__
  • 原型对象 prototype 有一个默认的 constructor 属性,用于记录实例是由哪个构造函数创建。

原型、原型链相等关系理解

有以下构造函数 Person,他的原型上有所属国属性 motherland=‘China’

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.motherland = "China";

通过 new Person()创建的 person01 实例

let person01 = new Person("小明", 18);

设计 js 原型、原型链的时候遵从以下两个准则:

  • 准则 1:原型对象(即Person.prototype)的constructor指向构造函数本身。即Person.prototype.constructor == Person
  • 准则 2:实例(即person01)的__proto__和原型对象指向同一个地方。即person01.__proto__ == Person.prototype
// 从上方 function Foo() 开始分析这一张经典之图
function Foo()
let f1 = new Foo();
let f2 = new Foo();

f1.__proto__ = Foo.prototype; // 准则2
f2.__proto__ = Foo.prototype; // 准则2
Foo.prototype.__proto__ = Object.prototype; // 准则2 (Foo.prototype本质也是普通对象,可适用准则2)
Object.prototype.__proto__ = null; // 原型链到此停止
Foo.prototype.constructor = Foo; // 准则1
Foo.__proto__ = Function.prototype; // 准则2
// 从中间 function Object()开始分析这一张经典之图
function Object()
let o1 = new  Object();
let o2 = new  Object();

o1.__proto__ = Object.prototype; // 准则2
o2.__proto__ = Object.prototype; // 准则2
Object.prototype.__proto__ = null; // 原型链到此停止
Object.prototype.constructor = Object; // 准则1
// 所有函数的__proto__  都和 Function.prototype指向同一个地方
Object.__proto__ = Function.prototype // 准则2 (Object本质也是函数);
// 此处有点绕
Function.prototype.__proto__ =  Object.prototype; // 准则2 (Function.prototype本质也是普通对象,可适用准则2)
// 从下方 function Function()开始分析这一张经典之图
function Function()
Function.__proto__ = Function.prototype // 准则2
Function.prototype.constructor = Function; // 准则1
function foo() { }
f1 = new foo();
f2 = new foo();
foo.prototype.x = "hello";

f1.x  => "hello"
f2.x  => "hello";

f1.x = "goodbye";   //setting f1.x hides foo.prototype.x

f1.x  => "goodbye"  //hides "hello" for f1 only
f2.x  => "hello"

delete f1.x
f1.x  => "hello";   //foo.prototype.x is visible again to f1.

除了Object的原型对象(Object.prototype)的__proto__指向null,其他内置函数对象的原型对象(例如:Array.prototype)和自定义构造函数的 __proto__都指向Object.prototype, 因为原型对象本身是普通对象。

Object.prototype.__proto__ = null;
Array.prototype.__proto__ = Object.prototype;
Foo.prototype.__proto__ = Object.prototype;

分析了这么多可以很清晰的画出下面这幅图。

原型、原型链的意义

原型对象的作用,是用来存放实例中共有的那部份属性、方法,可以大大减少内存消耗。

function Person(name, age) {
  this.name = name;
  this.age = age;
}
Person.prototype.motherland = "China";
let person01 = new Person("小明", 18);

打印person01, 他有自己属性 name = '小明'age = 18; 同时通过原型链关系,他有属性motherland = 'China'

let person02 = new Person("小花", 20);
console.log(person02);

打印person02, 他有自己属性 name = '小花'age = 20; 同时通过原型链关系,他有属性motherland = 'China'; 看出来了没有,原型对象存放了person01person02共有的属性所属国motherland = 'China'. 我们不用在每个实例上添加motherland 属性,而是将这一属性存在他们的构造函数原型对象上,对于人类Person这样的构造函数。相同的属性、方法还有很多很多,比如我们是黑头发,我们都有吃,睡这样一个方法,当相同的属性、方法越多,原型、原型链的意义越大。

Person.prototype.hairColor = "black";
Person.prototype.eat = function () {
  console.log(
    "We usually eat three meals a day."
  );
};
console.log(person01);
console.log(person02);

antcao.me © 2022-PRESENT

: 0x9aB9C...7ee7d