代码之家  ›  专栏  ›  技术社区  ›  Chris Noe Paweł Dyda

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

  •  24
  • Chris Noe Paweł Dyda  · 技术社区  · 14 年前

    只有3行代码,但我很难完全理解:

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

    (从 Prototypal Inheritance )

    1. Object.create() 首先创建一个名为 F . 我认为函数是一种物体。这个在哪里 f 正在存储的对象?我想是全球性的。

    2. 下一个我们的 oldObject ,作为传入 o 成为函数的原型 f . 功能(即对象) f 现在“继承”我们的 旧对象 从某种意义上说,名称解析将通过它。很好,但我很好奇对象的默认原型是什么,对象?对于函数对象也是这样吗?

    3. 最后, f 被实例化并返回,成为我们的 newObject . 是 new 这里必须严格操作吗?不 f 已经提供了我们需要的,或者函数对象和非函数对象之间是否存在关键区别?显然,使用这种技术不可能有一个构造函数函数。

    下次怎么办 对象。创建() 是否被调用?是全局函数 f 是否覆盖?当然,它不会被重用,因为这会改变以前配置的对象。如果多个线程调用 对象。创建() ,是否有任何类型的同步以防止在 f ?

    4 回复  |  直到 14 年前
        1
  •  29
  •   Christian C. Salvadó    14 年前

    1)object.create()开始于 创建一个名为f的空函数。 我认为函数是一种 对象的。这个F对象在哪里 正在存储?我想是全球性的。

    不,它存储在 Object.create 函数,每次调用 对象.创建 这个功能 F 将被重新创建。

    您甚至可以通过存储 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)接下来是我们的旧对象,作为o传入, 成为函数f的原型。 函数(即对象)f现在 “继承”来自我们的旧对象,在 感觉到名称解析将路由 通过它。很好,但我很好奇 默认原型用于 对象,对象?这也是真的吗 函数对象?

    所有对象都有一个构建原型链的内部属性,此属性称为 [[Prototype]] ,它是一个内部属性,尽管有些实现允许您访问它,如Mozilla,使用 obj.__proto__ 属性。

    违约 [原型]] 创建新对象时,即 var obj = {}; Object.prototype .

    所有函数都有一个 prototype 属性,当函数用作 Constructor ,用调用 new 操作员。

    它在后台创建的新对象实例,以及此对象 [原型]] 设置为其构造函数的 原型 属性。

    3)最后,F被实例化并 返回,成为我们的新对象。是 “新”操作是严格必要的 在这里?还没有提供什么 我们需要,还是有关键的 函数对象之间的差异 非功能对象呢?很明显 不可能有一个 使用此的构造函数函数 技术。

    是的, 新的 在这种方法中,运算符是必不可少的。

    这个 新的 操作员是设置 [原型]] 对象的内部属性,如果您对对象的工作方式感兴趣,可以查看 [[Construct]] 内部操作。

    下次怎么办 是否调用了object.create()?是全局的 函数f是否被覆盖?当然是这样 不能重复使用,因为那样会改变 以前配置的对象。和 如果多个线程调用 object.create(),是否有 同步以防止竞争 F上的条件?

    下次 对象.创建 被调用,一个新的本地 f 函数仅在方法调用的范围内实例化,您不必担心 竟态条件 .

    注意,这个实现几乎不符合 对象.创建 在中描述 ECMAScript 5th Edition Specification 在该方法中,可以传递属性描述符来初始化对象。

    所有浏览器供应商都在实现它(已经在firefox 3.7 alphas、最新的wekit Nightly版本和chrome 5 beta上提供),所以我建议您在覆盖它之前至少检查一下是否存在本机实现。

        2
  •  7
  •   Tim Down    14 年前

    1)函数实际上是一种对象。带有标识符的函数对象 F 每次都创建 Object.create 被调用,并且只能在执行 对象.创建 . 因此,每次 对象.创建 调用时,您将得到一个不同的函数对象 f . 此函数对象作为 constructor 返回的对象的属性 对象.创建 .

    2)

    现在“继承”我们的旧对象, 在这个意义上,名称解析将 穿过它

    这不太正确。分配对象 someObject prototype 函数的属性仅意味着通过将此函数作为构造函数调用而创建的任何未来对象的原型将 某个对象 .

    3) new 对这项技术至关重要。只有将函数作为构造函数调用,它才会生成一个新对象,并且该对象的原型(通常不可访问)被设置为构造函数的 原型 属性。没有其他(标准化的)方法来设置对象的原型。

    最后,浏览器中的javascript是单线程的,因此不可能出现如您所描述的竞争条件。

        3
  •  2
  •   spender    14 年前

    你在这里的主要误解是F具有全球范围。它在object.create的主体中声明,因此只在该方法块的范围内。

        4
  •  2
  •   John    13 年前

    >显然,使用这种技术不可能有一个构造函数函数。

    该技术已经是一个对象构造函数,因为它返回了新的f(),但是不能为say new man(“john”,“smith”)设置任何属性值。但是,如果修改了object.create代码,则可以进行实例化。例如,下面的Sarah对象可以使用object.creator构造和实例化,并将继承getname方法。

    var girl = {
       name: '',
       traits: {},
       getName: function(){return this.name}
    }
    
    var sarah = Object.creator(girl, 'Sarah', {age:29,weight:90})
    

    Sarah对象将由自己的属性名称:'Sarah',特性:年龄:9,重量:49,原型继承的Sarah.getName()将生成'Sarah'。

    以下方法依赖于以创建顺序使用“for(prop in o)”枚举的自身属性。虽然没有ECMA规范的保证,但这个例子(以及一些更复杂的例子)适用于所有测试过的主要浏览器(4),但使用了provided hasownpropy(),否则就不适用了。

    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()
    }
    

    官方的ecma object.create有一个可选的第二个参数propertiesObject,它可以实例化属性值,但它是一个对象,而不是通常的列表,并且看起来很难使用。例如,我相信:

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

    相当于更简单的老方法:

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

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