Crockford 的对象创建技术发生了什么?
只有 3 行代码,但我无法完全理解这一点:(
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
newObject = Object.create(oldObject);
来自 原型继承)
Object.create()
首先创建一个名为F
的空函数。我认为函数是一种对象。这个F
对象存储在哪里?我猜是全局性的。接下来我们的
oldObject
,作为o
传入,成为函数F
的原型。函数(即对象)F
现在从我们的oldObject
中“继承”,从某种意义上说,名称解析将通过它进行路由。很好,但我很好奇对象的默认原型是什么,Object?对于函数对象来说也是如此吗?最后,
F
被实例化并返回,成为我们的newObject
。这里的new
操作是绝对必要的吗?F
不是已经提供了我们需要的东西,还是函数对象和非函数对象之间存在关键区别?显然,使用这种技术不可能有一个构造函数。
下次调用 Object.create()
时会发生什么?全局函数F
是否被覆盖?当然它不会被重用,因为这会改变以前配置的对象。如果多个线程调用 Object.create()
会发生什么,是否有任何类型的同步来防止 F
上的竞争条件?
There are only 3 lines of code, and yet I'm having trouble fully grasping this:
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
newObject = Object.create(oldObject);
(from Prototypal Inheritance)
Object.create()
starts out by creating an empty function calledF
. I'm thinking that a function is a kind of object. Where is thisF
object being stored? Globally I guess.Next our
oldObject
, passed in aso
, becomes the prototype of functionF
. Function (i.e., object)F
now "inherits" from ouroldObject
, in the sense that name resolution will route through it. Good, but I'm curious what the default prototype is for an object, Object? Is that also true for a function-object?Finally,
F
is instantiated and returned, becoming ournewObject
. Is thenew
operation strictly necessary here? Doesn'tF
already provide what we need, or is there a critical difference between function-objects and non-function-objects? Clearly it won't be possible to have a constructor function using this technique.
What happens the next time Object.create()
is called? Is global function F
overwritten? Surely it is not reused, because that would alter previously configured objects. And what happens if multiple threads call Object.create()
, is there any sort of synchronization to prevent race conditions on F
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
不,它存储在
Object.create
函数的本地范围内,每次调用Object.create
时,都会重新创建此函数F
。您甚至可以通过将
F
存储在闭包上并重用它来创建内存效率更高的实现:所有对象都有一个构建原型链的内部属性,该属性称为
[[Prototype]]
,它是一个内部属性,尽管有些实现允许您访问它,例如 mozilla,使用 < code>obj.__proto__ 属性。创建新对象时,即
var obj = {};
,默认的[[Prototype]]
是Object.prototype
。所有函数都有一个
prototype
属性,当函数用作 构造函数,使用new
运算符调用。它在幕后创建一个新的对象实例,并将该对象
[[Prototype]]
设置为其构造函数的prototype
属性。是的,
new
运算符在此方法中至关重要。new
操作符是设置对象的[[Prototype]]
内部属性的唯一标准方法,如果你好奇它是如何工作的,你可以看一下到[[Construct]]
内部运作。下次调用
Object.create
时,仅在方法调用的范围内实例化新的本地F
函数,您不必担心竞争条件 。请注意,此实现几乎不符合 ECMAScript 第五版规范,在该方法中,您可以传递一个属性描述符来初始化对象。
所有浏览器供应商都在实现它(已经在 Firefox 3.7 alpha、最新的 Wekit Nightly Builds 和 Chrome 5 Beta 上可用),所以我建议您至少在覆盖它之前检查是否存在本机实现。
No, it's stored on the local scope of the
Object.create
function, each time you invokeObject.create
this functionF
will be recreated.You could even create a more memory-efficient implementation, by storing
F
on a closure, and reuse it:All objects have an internal property that builds the prototype chain, this property is known as
[[Prototype]]
, it's an internal property, although some implementations let you access to it, like mozilla, with theobj.__proto__
property.The default
[[Prototype]]
when you create a new object, i.e.var obj = {};
isObject.prototype
.All functions have a
prototype
property, this property is used when a function is used as a Constructor, invoked with thenew
operator.A new object instance it's created behind the scenes, and this object
[[Prototype]]
is set to its Constructor'sprototype
property.Yes, the
new
operator is essential in this method.The
new
operator is the only standard way to set the[[Prototype]]
internal property of an object, if you are curious about how it works, you can give a look to the[[Construct]]
internal operation.The next time
Object.create
is invoked, a new localF
function is instantiated only within the scope of the method call, you shouldn't worry about race conditions.Note that this implementation hardly conforms the
Object.create
described in the ECMAScript 5th Edition Specification, in that method, you could pass a property descriptor to initialize the object.All browser vendors are implementing it (already available on Firefox 3.7 alphas, latest Wekit Nightly Builds and Chrome 5 Beta), so I would recommend you at least to check if a native implementation exist before overriding it.
1)函数确实是一种对象。每次调用
Object.create
时都会创建一个带有标识符F
的函数对象,并且只能在执行Object.create
时使用该标识符进行访问>。因此,每次调用Object.create
时,您都会得到一个不同的函数对象F
。该函数对象作为Object.create
返回的对象的constructor
属性存在。2)
这并不正确。将对象
someObject
分配给函数的prototype
属性仅意味着通过调用此函数作为构造函数创建的任何未来对象的原型将是someObject.
3)
new
对于这项技术来说绝对至关重要。只有通过将函数作为构造函数调用,它才会生成一个新对象,并且该对象的原型(通常不可访问)被设置为构造函数的prototype
属性。没有其他(标准化)方法来设置对象的原型。最后,浏览器中的 JavaScript 是单线程的,因此不可能出现您所描述的竞争条件。
1) A function is indeed a kind of object. A function object with identifier
F
is created each timeObject.create
is called, and is only accessible with that identifier within that execution ofObject.create
. Therefore, each timeObject.create
is called, you get a different function objectF
. This function object lives on as theconstructor
property of the object returned byObject.create
.2)
This isn't really correct. Assigning an object
someObject
to theprototype
property of a function just means that the prototype of any future object created by calling this function as a constructor will besomeObject
.3) The
new
is absolutely vital to this technique. Only by calling a function as a constructor does it produce a new object, and that object's prototype (which is not generally accessible) is set to the constructor function'sprototype
property. There is no other (standardised) way to set an object's prototype.Finally, JavaScript in browsers is single threaded, so race conditions such as you describe are not possible.
您在这里的主要误解是 F 具有全球范围。它是在 Object.create 的主体中声明的,因此仅在该方法块的范围内。
Your major misunderstanding here is that F has global scope. It is declared in the body of Object.create and consequently is only in scope within that method block.
该技术已经是一个对象构造函数,因为它返回 new F(),但不能像 new man('John','Smith') 那样设置属性值。但是,如果修改 Object.create 代码,则可以进行实例化。例如下面的 sarah 对象可以使用 Object.creator 构造和实例化,并将继承 getName 方法。
sarah 对象将由自己的属性 { name:'Sarah', Traits:{age:9,weight:49} } 组成,并且继承 sarah.getName() 的原型将生成 'Sarah'。
以下方法依赖于按创建顺序使用“for(prop in o)”枚举的自己的属性。尽管 ECMA 规范没有保证,但这个示例(以及一些更复杂的示例)适用于所有经过测试的主要浏览器 (4),前提是使用了 hasOwnProperty(),否则则不然。
官方的ECMA Object.create有一个可选的第二个参数propertiesObject,它可以实例化属性值,但它是一个对象而不是通常的列表,并且使用起来看起来很尴尬。例如,我相信:-
相当于更简单的旧方法:-
和
The technique is already an object constructor since it returns new F(), but no property values can be set as for say new man('John','Smith'). However, if the Object.create code is modified, instantiation is possible. For example the sarah object below can be constructed and instantiated using Object.creator, and will inherit the getName method.
The sarah object will then consist of own properties { name:'Sarah', traits:{age:9,weight:49} }, and the prototype inherited sarah.getName() will produce 'Sarah'.
The following method relies on own properties enumerating with 'for(prop in o)' in creation order. Although not guaranteed by ECMA specs, this example (and a few more complex) worked for all major browsers (4) tested, providied hasOwnProperty() was used, otherwise not.
The official ECMA Object.create has an optional 2nd parameter, propertiesObject, that can instantiate property values, but it is an object rather than the usual list, and looks awkward to use. E.g. I believe:-
is equivalent to the much simpler old way:-
and