WebHub
WebHub copied to clipboard
原型相关长期收录
参考资料
要点
- 每个实例对象( object )都有一个私有属性(称之为 proto )指向它的构造函数的原型对象(prototype )
- JavaScript 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾
-
实例.__proto__=== 原型 - 原型.constructor === 构造函数
- 构造函数.prototype === 原型
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 === 原型
- 当谈到继承时,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 === 构造函数
-
__proto__是原型链查询中实际用到的,它总是指向 prototype; - prototype 在定义构造函数时自动创建,它总是被 proto 所指。
- 从上面两点我们还可以推出 prototype 只能作为构造函数的属性,
-
__proto__可以作为任意对象的属性。
关于模拟实现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}
关于原型链继承的几种方式
- 继承与原型链
- 原型链以及继承的几种方式
- 几种方式
- new的方式继承(B.prototype = new A)
- Object.create(B.prototype = Object.create(foo.prototype))