简体   繁体   English

Crockford的对象创建技术发生了什么?

[英]What is happening in Crockford's object creation technique?

There are only 3 lines of code, and yet I'm having trouble fully grasping this: 只有3行代码,但我很难完全掌握这个:

Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
};
newObject = Object.create(oldObject);

(from Prototypal Inheritance ) (来自Prototypal Inheritance

  1. Object.create() starts out by creating an empty function called F . Object.create()从创建一个名为F的空函数开始。 I'm thinking that a function is a kind of object. 我认为函数是一种对象。 Where is this F object being stored? 这个F对象存放在哪里? Globally I guess. 在全球范围内我猜。

  2. Next our oldObject , passed in as o , becomes the prototype of function F . 接下来,作为o传入的oldObject成为函数F的原型。 Function (ie, object) F now "inherits" from our oldObject , in the sense that name resolution will route through it. 函数(即对象) F现在从我们的oldObject “继承”,在名称解析将路由它的意义上。 Good, but I'm curious what the default prototype is for an object, Object? 很好,但我很好奇默认原型是什么对象,对象? Is that also true for a function-object? 这对于函数对象也是如此吗?

  3. Finally, F is instantiated and returned, becoming our newObject . 最后, F被实例化并返回,成为我们的newObject Is the new operation strictly necessary here? 这里new操作是否必要? Doesn't F already provide what we need, or is there a critical difference between function-objects and non-function-objects? F是否已经提供了我们需要的东西,或者功能对象和非功能对象之间是否存在重要区别? Clearly it won't be possible to have a constructor function using this technique. 显然,使用这种技术不可能有一个构造函数。

What happens the next time Object.create() is called? 下次调用Object.create()时会发生什么? Is global function F overwritten? 全局函数F被覆盖? 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 ? 如果多个线程调用Object.create()会发生什么,是否有任何同步来防止F上的竞争条件?

1) Object.create() starts out by creating an empty function called F. I'm thinking that a function is a kind of object. 1)Object.create()从创建一个名为F的空函数开始。我认为函数是一种对象。 Where is this F object being stored? 这个F对象存放在哪里? Globally I guess. 在全球范围内我猜。

No, it's stored on the local scope of the Object.create function, each time you invoke Object.create this function F will be recreated. 不,它存储在Object.create函数的本地范围内,每次调用Object.create都会重新创建此函数F

You could even create a more memory-efficient implementation, by storing F on a closure, and reuse it: 您甚至可以通过将F存储在闭包上来创建更具内存效率的实现,并重用它:

if (typeof Object.create !== "function") {
  Object.create = (function () {
    function F() {} // created only once
    return function (o) {
      F.prototype = o; // reused on each invocation
      return new F();
    };
  })();
}

2) Next our oldObject, passed in as o, becomes the prototype of function F. Function (ie, object) F now "inherits" from our oldObject, in the sense that name resolution will route through it. 2)接下来,作为o传入的oldObject成为函数F的原型。函数(即对象)F现在从我们的oldObject“继承”,在名称解析将通过它的路径中。 Good, but I'm curious what the default prototype is for an object, Object? 很好,但我很好奇默认原型是什么对象,对象? Is that also true for a function-object? 这对于函数对象也是如此吗?

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 the obj.__proto__ property. 所有对象都有一个构建原型链的内部属性,这个属性称为[[Prototype]] ,它是一个内部属性,虽然有些实现允许你使用obj.__proto__属性访问它,比如mozilla。

The default [[Prototype]] when you create a new object, ie var obj = {}; 创建新对象时的默认[[Prototype]] ,即var obj = {}; is Object.prototype . Object.prototype

All functions have a prototype property, this property is used when a function is used as a Constructor , invoked with the new operator. 所有函数都有一个prototype属性,当一个函数用作构造函数时,使用此属性,并使用new运算符调用。

A new object instance it's created behind the scenes, and this object [[Prototype]] is set to its Constructor's prototype property. 它是在幕后创建的一个新对象实例,此对象[[Prototype]]设置为其Constructor的prototype属性。

3) Finally, F is instantiated and returned, becoming our newObject. 3)最后,F被实例化并返回,成为我们的newObject。 Is the "new" operation strictly necessary here? 这里的“新”操作是否严格必要? Doesn't F already provide what we need, or is there a critical difference between function-objects and non-function-objects? F是否已经提供了我们需要的东西,或者功能对象和非功能对象之间是否存在重要区别? Clearly it won't be possible to have a constructor function using this technique. 显然,使用这种技术不可能有一个构造函数。

Yes, the new operator is essential in this method. 是的, new算子在这种方法中至关重要。

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. new运算符是设置对象[[Prototype]]内部属性的唯一标准方法,如果您对它的工作原理感到好奇,可以查看[[Construct]]内部操作。

What happens the next time Object.create() is called? 下次调用Object.create()时会发生什么? Is global function F overwritten? 全局函数F是否被覆盖? 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? 如果多个线程调用Object.create()会发生什么,是否有任何同步来防止F上的竞争条件?

The next time Object.create is invoked, a new local F function is instantiated only within the scope of the method call, you shouldn't worry about race conditions . 下一次调用Object.create ,只在方法调用的范围内实例化一个新的本地F函数,你不应该担心竞争条件

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. 请注意,此实现几乎不符合ECMAScript第5版规范中描述的Object.create ,在该方法中,您可以传递属性描述符来初始化对象。

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. 所有浏览器供应商都在实现它(已经在Firefox 3.7 alphas,最新的Wekit Nightly Builds和Chrome 5 Beta上提供),所以我建议你至少在覆盖它之前检查本机实现是否存在。

1) A function is indeed a kind of object. 1)函数确实是一种对象。 A function object with identifier F is created each time Object.create is called, and is only accessible with that identifier within that execution of Object.create . 每次调用Object.create都会创建一个带有标识符F函数对象,并且只能在Object.create执行中使用该标识符访问该函数对象。 Therefore, each time Object.create is called, you get a different function object F . 因此,每次调用Object.create ,都会得到一个不同的函数对象F This function object lives on as the constructor property of the object returned by Object.create . 此函数对象作为Object.create返回的对象的constructor属性而存在。

2) 2)

F now "inherits" from our oldObject, in the sense that name resolution will route through it F现在从我们的oldObject“继承”,在名称解析将通过它的路上

This isn't really correct. 这不是真的正确。 Assigning an object someObject to the prototype property of a function just means that the prototype of any future object created by calling this function as a constructor will be someObject . 将对象someObject分配给函数的prototype属性只意味着通过将此函数作为构造函数创建的任何未来对象的原型将是someObject

3) The new is absolutely vital to this technique. 3) new技术对这项技术至关重要。 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's prototype property. 只有通过调用函数作为构造函数才能生成新对象,并且该对象的原型(通常不可访问)将设置为构造函数的prototype属性。 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. 最后,浏览器中的JavaScript是单线程的,因此您描述的竞争条件是不可能的。

Your major misunderstanding here is that F has global scope. 你在这里的主要误解是F具有全球范围。 It is declared in the body of Object.create and consequently is only in scope within that method block. 它在Object.create的主体中声明,因此仅在该方法块的范围内。

> Clearly it won't be possible to have a constructor function using this technique. >显然,使用这种技术不可能有构造函数。

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'). 该技术已经是一个对象构造函数,因为它返回了新的F(),但是没有设置属性值,就像说新人('John','Smith')一样。 However, if the Object.create code is modified, instantiation is possible. 但是,如果修改了Object.create代码,则可以实例化。 For example the sarah object below can be constructed and instantiated using Object.creator, and will inherit the getName method. 例如,下面的sarah对象可以使用Object.creator构造和实例化,并将继承getName方法。

var girl = {
   name: '',
   traits: {},
   getName: function(){return this.name}
}

var sarah = Object.creator(girl, 'Sarah', {age:29,weight:90})

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'. 然后sarah对象将包含自己的属性{name:'Sarah',traits:{age:9,weight:49}},继承sarah.getName()的原型将生成'Sarah'。

The following method relies on own properties enumerating with 'for(prop in o)' in creation order. 以下方法依赖于在创建顺序中使用'for(prop in o)'枚举的自有属性。 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. 虽然ECMA规范没有保证,但这个例子(以及一些更复杂的例子)适用于所有测试的主要浏览器(4),但是使用了提供的hasOwnProperty(),否则没有。

Object.creator = function(o) {
   var makeArgs = arguments 
   function F() {
      var prop, i=1, arg, val
      for(prop in o) {
         if(!o.hasOwnProperty(prop)) continue
         val = o[prop]
         arg = makeArgs[i++]
         if(typeof arg === 'undefined') break
         this[prop] = arg
      }
   }
   F.prototype = o
   return new F()
}

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. 官方ECMA Object.create有一个可选的第二个参数propertiesObject,它可以实例化属性值,但它是一个对象而不是通常的列表,看起来很难使用。 Eg I believe:- 我相信: -

o2 = Object.create({}, { p: { value: 42, writable: true, enumerable: true, configurable: true } });

is equivalent to the much simpler old way:- 相当于更简单的旧方式: -

o2 = new function(p) { this.p=p }(42)

and

o2 = Object.creator({p:''}, 42)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM