JavaScript是如何生成一个对象的?

JavaScript 是一种基于原型(prototype-based)的面向对象语言。在 JavaScript 中,每一个实例对象都有一个与之相关联的原型链,通过原型链与继承关系,JavaScript 定义了对象的属性。

原型链

每个实例对象都有一个私有属性(__proto__)指向它的原型(prototype),该原型也有自己的原型,如此不断向上就会形成一个原型链。原型链的终点为nullnull不存在原型。在控制台中运行代码可以看到如下日志,其中o.__proto__就指向对象o的原型。

var o = { a: 1 }
console.log(o) // { a: 1, __proto__: Object}
复制代码

遵循 ECMAScript 标准,someObject.[[Prototype]]符号是用于指向someObject的原型。从 ECMAScript 6 开始,[[Prototype]]可以通过Object.getPrototypeOf()Object.setPrototypeOf()访问器来访问。这个等同于 JavaScript 的非标准但许多浏览器实现的属性 __proto__。 接下来我们使用Object.create以对象o为原型创建对象p。然后改变o.a的值,观察p.a的值的变化。

var p = Object.create(o)
console.log(p.a) // 1
console.log(p.__proto__===o) // true
// 完整的原型链是:p ---> o ---> Object.prototype --->null,其中Object.prototype代表Object的原型对象
o.a = 2
console.log(p.a) // 2
// 由于p的属性a继承自o,改变o.a的值,p.a的值也会随之改变
复制代码

现在我们以p为原型创建对象q,并重新赋值p.a

p.a = function () {
  this.x = 1
  this.y = 2
}
var q = Object.create(p)
console.log(q.__proto__===p) // true
// 完整的原型链是: q ---> p ---> o ---> Object.prototype ---> null
console.log(q.a) // f () { this.x = 1; this.y = 1 }
// q的属性a继承自原型链上的p
o.b = 3
console.log(q.b) // 3
// q的属性b继承自原型链上的o
console.log(o.c) // undefined
复制代码

当访问q的某一属性的时候,如果q本身没有这个属性,就会在q的原型p中寻找有没有名称匹配的属性,如果有则返回该属性的值,如果没有则继续向上寻找p的原型o中有没有名称匹配的属性,如此向上追溯直至原型链的终点。

When trying to access a property of an object, the property will not only be sought on the object but on the prototype of the object, the prototype of the prototype, and so on until either a property with a matching name is found or the end of the prototype chain is reached.

在 JavaScript 中,任意一个对象都有一个与之相关联的原型链,试图访问该对象的某个属性时,除了对象本身之外,还会访问与其关联的原型链,直到找到名称匹配的第一个属性或者到达原型链的终点为止。

prototype__proto__

上文已经提到,在原型链q ---> p ---> o ---> Object.prototype ---> null中, Object.prototype代表Object的原型对象。与对象的私有属性__proto__指向对象的原型不同,prototype是函数(Function)特有的属性。在控制台中运行如下代码:

var f = function(x, y) {
    this.x = x
    this.y = y
}
console.log(f.prototype) // {constructor: f (x,y), __proto__: Object}
var o = new f(1,2)
console.log(o.__proto__===f.prototype) // true
console.log(f.prototype.__proto__===Object.prototype) // true
// 完整的原型链是:o ---> f.prototype ---> Object.prototype ---> null
复制代码

原型链上的每一环均为对象,实例对象(instance)与原型对象(prototype)。实例对象处于原型链的下游,其源自原型对象,原型对象处于原型链的上游,原型链的顶端是Object.prototype。因此,在 JavaScript 中几乎所有的对象都是位于原型链顶端的Object构造函数构造的实例。

根据这一点,我们可以通过改变构造函数的prototype来改变实例的属性。

f.prototype.z = function() {
  this.a = 'a'
  this.b = 'b'
}
console.log(o.z) // function() { this.a='a' this.b='b' }
复制代码

可以说 JavaScript 中的所有对象均由函数以构造函数生成,都源自函数的原型对象。而函数本身其实也是一种对象(Function对象),它们可以像对象一样具有属性和方法。因此经常说函数是 JavaScript 的头等公民(first-class object)。

参考文章

Inheritance and the prototype chain

Details of the object model

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值