JS原型及原型链

141 阅读2分钟

JavaScript原型及原型链

  • 第一次写这种技术类的公开笔记,有些思路不知道如何用更好的语言去组织表达清晰,希望看到的各位看官,不喜勿喷,如果有错误的地方,欢迎指正。

JS的类型

  • 分为基本类型和引用类型,
    • 基本类型:number,string,boolean,undefined,null,bigInt,symbol
    • 引用类型:Object
      • 基本引用类型
        • Date RegExp
        • 原始值包装类型 Number String Boolean
        • 单例内置对象 Global Math
      • 集合引用类型
        • Object
        • Array
        • ArrayBuffer 定型数组
        • Map
        • WeakMap
        • Set
        • WeakSet
        • ...

对JS来讲,使用最多的当属对象

JS万物可对象

  • 创建对象的常见两种方式
    • 通过字面量形式
    • 通过new操作符

构造函数本身也是Function的一个对象实例, 也可叫做函数对象,

  • 函数对象内部有[[call]]、[[constructor]]属性,
  • 使用new构造函数,用[[constructor]]属性
  • 普通调用时,用[[call]]属性

那使用 new 操作符,通过new操作符调用构造函数会执行什么操作?

  1. 在内存中创建一个对象
  2. 这个新对象内部的[[Prototype]]特性被赋值为构造函数的 prototype 属性。
  3. 构造函数内部的 this 被赋值为这个新对象(即 this 指向新对象)。
  4. 执行构造函数内部的代码(给新对象添加属性)。
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的新对象。

在上述创建对象过程中,new操作符创建的实例对象上,包含隐式原型属性__proto__, 构造函数对象上有显示原型prototype属性, 实例对象隐式原型属性指向构造函数对象的显示原型prototype。 同理构造函数对象上也有隐式原型属性__proto__,指向Function.prototype,Function原型的尽头是null。 构造函数对象的原型对象上有constructor属性,且指向构造函数对象。

注:ES6中定义了 Object.setPrototypeOf 以及 Object.getPrototypeOf

// 定义Parent构造函数
function Parent(param) {
    this.name = "parent";
    this.fruits = ["apple","banana"];
    this.param = param;
    this.getName = function() {
        console.log(this.name);
        console.log(this.param);
    }
}
// 给Parent原型对象上添加方法
Parent.prototype.say = function() {
    console.log(this.name + "," + this.param);
}

// 用Parent创建实例p1
let p1 = new Parent("p1 param");
p1.fruits.push("strabrew");
// console.log(p1.fruits);;
p1.getName();
p1.say();

console.log(p1 instanceof Parent); // true
console.log(Parent.prototype instanceof Parent) // false
console.log(p1.__proto__ == Parent.prototype); // true
console.log(p1.__proto__.constructor == Parent); // true;
console.log(Parent.prototype.constructor == Parent); // true;
console.log(Parent.prototype.__proto__ instanceof Parent); // false
console.log(Parent.prototype.__proto__ === Object.prototype); // true
// 对象分:函数对象和普通对象,函数对象只添加prototype属性,函数对象也是对象,也有construcor和__proto__属性
console.log(Parent.constructor == Function); // true
console.log(Parent.__proto__ == Function.prototype); // true
console.log(p1.prototype); // undefined

原型链

ECMA-262 把原型链定义为 ECMAScript 的主要继承方式。其基本思想就是通过原型继承多个引用类型的属性和方法。 原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。这就是原型链的基本构想。