WebHub icon indicating copy to clipboard operation
WebHub copied to clipboard

原型相关长期收录

Open ckinmind opened this issue 9 years ago • 5 comments

参考资料

要点

  • 每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )
  • JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
  • 实例.__proto__ === 原型
  • 原型.constructor === 构造函数
  • 构造函数.prototype === 原型

ckinmind avatar Nov 01 '16 12:11 ckinmind

1.原型 / 构造函数 / 实例

  • 原型(prototype): 一个简单的对象,用于实现对象的 属性继承。可以简单的理解成对象的爹。在 Firefox 和 Chrome 中,每个JavaScript对象中都包含一个__proto__ (非标准)的属性指向它爹(该对象的原型),可obj.__proto__进行访问
  • 构造函数: 可以通过new来 新建一个对象 的函数
  • 实例: 通过构造函数和new创建出来的对象,便是实例。 实例通过__proto__指向原型,通过constructor指向构造函数
// 实例
const instance = new Object()

// 原型
const prototype = Object.prototype

// 这条线其实是是基于原型进行获取的,可以理解成一条基于原型的映射线
// 例如: 
// const o = new Object()
// o.constructor === Object   --> true
// o.__proto__ = null;
// o.constructor === Object   --> false

// 实例.__proto__ === 原型
// 原型.constructor === 构造函数
// 构造函数.prototype === 原型

ckinmind avatar Nov 06 '19 08:11 ckinmind

MDN:继承与原型链

  • 当谈到继承时,JavaScript 只有一种结构:对象。每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )。该原型对象也有一个自己的原型对象( proto ) ,层层向上直到一个对象的原型对象为 null。根据定义,null 没有原型,并作为这个原型链中的最后一个环节
    • 实例对象有私有属性_proto_
    • 构造函数的原型对象prototype
  • 几乎所有 JavaScript 中的对象都是位于原型链顶端的 Object 的实例
  • JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
  • 遵循ECMAScript标准,someObject.[[Prototype]] 符号是用于指向 someObject 的原型。从 ECMAScript 6 开始,[[Prototype]] 可以通过 Object.getPrototypeOf() 和 Object.setPrototypeOf() 访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 proto
  • 给对象设置属性会创建自有属性。获取和设置属性的唯一限制是内置 getter 或 setter 的属性
var o = {a: 1}
o.__proto__ === Object.prototype // true
Object.prototype.__proto__ === null // true
// 原型链为 o ===> Object.prototype ===> null
function Graph() {
  this.vertices = [];
  this.edges = [];
}

Graph.prototype = {
  addVertex: function(v){
    this.vertices.push(v);
  }
};

var g = new Graph();
// g 是生成的对象,他的自身属性有 'vertices' 和 'edges'。
// 在 g 被实例化时,g.[[Prototype]] 指向了 Graph.prototype
// g.__proto__ === Graph.prototype  实例.__proto__ === 构造函数.prototype
// Graph.prototype.constructor === Graph 原型.constructor === 构造函数

ckinmind avatar Dec 08 '19 07:12 ckinmind

JavaScript 原型链

  • __proto__ 是原型链查询中实际用到的,它总是指向 prototype;
  • prototype 在定义构造函数时自动创建,它总是被 proto 所指。
  • 从上面两点我们还可以推出 prototype 只能作为构造函数的属性,
  • __proto__可以作为任意对象的属性。

ckinmind avatar Dec 08 '19 09:12 ckinmind

关于模拟实现new关键字

模拟实现new关键字

  • new做了什么
    • 创建一个对象
    • 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
    • 执行构造函数中的代码(为这个新对象添加属性)
    • 返回新对象
  • mdn中说的new做了什么:mdn:new
    • 创建一个空的简单JavaScript对象(即{})
    • 接该对象(即设置该对象的构造函数)到另一个对象
    • 将步骤1新创建的对象作为this的上下文
    • 如果该函数没有返回对象,则返回this
let myNew = function (constructor) {
    if (!(constructor instanceof Function)) { throw new Error('arguments[0] require a function')};
    let restArgs = Array.prototype.slice.call(arguments, 1);

    // 创建一个对象
    let instance = {};
    instance.__proto__ = constructor.prototype;

    // 将构造函数的作用域赋给新对象(因此this就指向了这个新对象) && 执行构造函数中的代码(为这个新对象添加属性)
    let result = constructor.apply(instance, restArgs);

    // 返回新对象
    return result instanceof Object ? result : instance;
}
console.log(myNew(Person, 'Alex', 22)) // {name: 'Alex', age: 22}

ckinmind avatar Dec 08 '19 11:12 ckinmind

关于原型链继承的几种方式

ckinmind avatar Dec 08 '19 12:12 ckinmind