代码之家  ›  专栏  ›  技术社区  ›  Graham King ptim

使用“Object.create”而不是“new”

  •  348
  • Graham King ptim  · 技术社区  · 16 年前

    Object.create 道格拉斯·克罗克福德和其他人一样 advocating new 在下面的代码中 对象.创建

    var UserA = function(nameParam) {
        this.id = MY_GLOBAL.nextId();
        this.name = nameParam;
    }
    UserA.prototype.sayHello = function() {
        console.log('Hello '+ this.name);
    }
    var bob = new UserA('bob');
    bob.sayHello();
    

    MY_GLOBAL.nextId 存在)。

    我能想到的最好办法是:

    var userB = {
        init: function(nameParam) {
            this.id = MY_GLOBAL.nextId();
            this.name = nameParam;
        },
        sayHello: function() {
            console.log('Hello '+ this.name);
        }
    };
    var bob = Object.create(userB);
    bob.init('Bob');
    bob.sayHello();
    

    似乎没有什么优势,所以我想我没有得到。我可能太新古典主义了。我该怎么用 要创建用户“bob”?

    14 回复  |  直到 7 年前
        1
  •  260
  •   Christian C. Salvadó    16 年前

    由于只有一个继承级别,您的示例可能无法让您看到 Object.create

    此方法允许您轻松地实现 差异遗传 ,其中对象可以直接从其他对象继承。

    在你的 userB init 方法应该是public甚至exist,如果对现有对象实例再次调用此方法,则 id name 属性将更改。

    对象.创建 允许您使用第二个参数初始化对象属性,例如:

    var userB = {
      sayHello: function() {
        console.log('Hello '+ this.name);
      }
    };
    
    var bob = Object.create(userB, {
      'id' : {
        value: MY_GLOBAL.nextId(),
        enumerable:true // writable:false, configurable(deletable):false by default
      },
      'name': {
        value: 'Bob',
        enumerable: true
      }
    });
    

    对象.创建 ,对象文字的语法与 Object.defineProperties Object.defineProperty 方法。

    enumerable , writable configurable ),非常有用。

        2
  •  54
  •   7ochem    8 年前

    使用它真的没有什么好处 Object.create(...) 结束 new object .

    "scalability" ,或“ more natural to JavaScript

    然而,我还没有看到一个具体的例子表明这一点 Object.create 任何 与使用相比的优势 new . 相反,它有一些已知的问题。 Sam Elsamman describes what happens when there are nested objects and Object.create(...) is used :

    var Animal = {
        traits: {},
    }
    var lion = Object.create(Animal);
    lion.traits.legs = 4;
    var bird = Object.create(Animal);
    bird.traits.legs = 2;
    alert(lion.traits.legs) // shows 2!!!
    

    这是因为 数据 Animal 基准成为原型的一部分 lion bird ,并在共享时引发问题。使用new时,原型继承是显式的:

    function Animal() {
        this.traits = {};
    }
    
    function Lion() { }
    Lion.prototype = new Animal();
    function Bird() { }
    Bird.prototype = new Animal();
    
    var lion = new Lion();
    lion.traits.legs = 4;
    var bird = new Bird();
    bird.traits.legs = 2;
    alert(lion.traits.legs) // now shows 4
    

    关于,传递到 ,可以使用 Object.defineProperties(...) .

        3
  •  42
  •   outis    14 年前

    Object.create在一些浏览器上还不是标准的,例如IE8、Opera v11.5、konq4.3都没有。您可以使用Douglas Crockford的Object.create版本,但这不包括CMS答案中使用的第二个“initialization Object”参数。

    对于跨浏览器代码,同时获得对象初始化的一种方法是定制Crockford的object.create。这里有一个method:-

    Object.build = function(o) {
       var initArgs = Array.prototype.slice.call(arguments,1)
       function F() {
          if((typeof o.init === 'function') && initArgs.length) {
             o.init.apply(this,initArgs)
          }
       }
       F.prototype = o
       return new F()
    }
    

    MY_GLOBAL = {i: 1, nextId: function(){return this.i++}}  // For example
    
    var userB = {
        init: function(nameParam) {
            this.id = MY_GLOBAL.nextId();
            this.name = nameParam;
        },
        sayHello: function() {
            console.log('Hello '+ this.name);
        }
    };
    var bob = Object.build(userB, 'Bob');  // Different from your code
    bob.sayHello();
    

    所以bob继承了sayHello方法,现在拥有自己的属性id=1和name='bob'。当然,这些属性既可写又可枚举。这也是一种比ECMA Object.create简单得多的初始化方法,特别是当您不关心可写、可枚举和可配置属性时。

    对于没有init方法的初始化,可以使用以下Crockford modused:-

    Object.gen = 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()
    }
    

    MY_GLOBAL = {i: 1, nextId: function(){return this.i++}};  // For example
    
    var userB = {
       name: null,
       id: null,
       sayHello: function() {
          console.log('Hello '+ this.name);
       }
    }
    
    var bob = Object.gen(userB, 'Bob', MY_GLOBAL.nextId());
    

    我觉得比Object.build要简单一些,因为userB不需要init方法。另外,userB不是一个具体的构造函数,而是一个普通的单例对象。所以用这个方法你可以构造和初始化普通的对象。

        4
  •  25
  •   NamiW    7 年前

    热释光;博士:

    new Computer() 将调用构造函数 Computer(){} Object.create(Computer.prototype) 不会。

    所有的优势都是基于这一点。

    新计算机() 在发动机上进行了大量优化,因此它可能比 Object.create .

        5
  •  14
  •   samfrances    14 年前

    你可以让 init 方法返回 this

    var userB = {
        init: function(nameParam) {
            this.id = MY_GLOBAL.nextId();
            this.name = nameParam;
            return this;
        },
        sayHello: function() {
            console.log('Hello '+ this.name);
        }
    };
    
    var bob = Object.create(userB).init('Bob');
    
        6
  •  10
  •   basos    13 年前

    Object.create的另一个可能用法是在 cheap and effective way .

    var anObj = {
        a: "test",
        b: "jest"
    };
    
    var bObj = Object.create(anObj);
    
    bObj.b = "gone"; // replace an existing (by masking prototype)
    bObj.c = "brand"; // add a new to demonstrate it is actually a new obj
    
    // now bObj is {a: test, b: gone, c: brand}
    

    笔记 1 ),因为它不复制对象成员属性。相反,它在源对象上创建另一个带有原型集的目标对象。此外,当dest对象上的属性被修改时,它们被“动态”创建,掩盖了原型(src)的属性,这是一种快速而有效的克隆不可变对象的方法。

    这里需要注意的是,这适用于创建后不应修改的源对象(不可变)。如果源对象在创建后被修改,克隆的所有未屏蔽属性也将被修改。

    在这里摆弄( http://jsfiddle.net/y5b5q/1/ )(需要具有Object.create功能的浏览器)。

        7
  •  7
  •   cn007b Dheerendra Kulkarni    9 年前

    new Object.create 方法。相应地 this answer this video 新的 关键字执行以下操作:

    1. 创建新对象。

    2. prototype ).

    3. 制造 this 变量指向新对象。

    4. 使用新对象和隐式perform执行构造函数 return this ;

    5. constructor .

    仅执行 1st 2nd 步骤!!!

    在本文提供的代码示例中,这并不是什么大事,但在下一个示例中,它是:

    var onlineUsers = [];
    function SiteMember(name) {
        this.name = name;
        onlineUsers.push(name);
    }
    SiteMember.prototype.getName = function() {
        return this.name;
    }
    function Guest(name) {
        SiteMember.call(this, name);
    }
    Guest.prototype = new SiteMember();
    
    var g = new Guest('James');
    console.log(onlineUsers);
    

    副作用结果如下:

    [ undefined, 'James' ]
    

    Guest.prototype = new SiteMember();
    但我们不需要执行父构造函数方法,我们只需要make方法 getName 在客房内提供。 .
    Guest.prototype=新建SiteMember();
    Guest.prototype = Object.create(SiteMember.prototype); 结果是:

    [ 'James' ]
    
        8
  •  6
  •   Supersharp    11 年前

    有时不能使用NEW创建对象,但仍然可以调用create方法。

    proto = new HTMLElement  //fail :(
    proto = Object.create( HTMLElement.prototype )  //OK :)
    document.registerElement( "custom-element", { prototype: proto } )
    
        9
  •  4
  •   frooble    12 年前

    优点是 Object.create 通常比 new 在大多数浏览器上

    In this jsperf example ,在浏览器中 新的 快30倍 Object.create(obj) 虽然两者都很快。这很奇怪,因为new做了更多的事情(比如调用构造函数),其中Object.create应该只是创建一个新对象,并将传入的对象作为原型(Crockford中的秘密链接)

    也许浏览器还没有赶上 对象.创建 效率更高(也许他们是基于 新的

        10
  •  4
  •   Willem van der Veen    7 年前

    • Object.create() 是一个Javascript函数,它接受2个参数并返回一个新对象。
    • 第一个参数是一个对象,它将是新创建的对象的原型
    • 第二个参数是一个对象,它将是新创建的对象的属性

    例子:

    const proto = {
      talk : () => console.log('hi')
    }
    
    const props = {
      age: {
        writable: true,
        configurable: true,
        value: 26
      }
    }
    
    
    let Person = Object.create(proto, props)
    
    console.log(Person.age);
    Person.talk();

    1. 以这种方式创建对象的主要优点是 原型可以明确定义 new
    2. 如果我们想要一个原型 关键字调用构造函数。与 不需要调用甚至声明构造函数 .
    3. 当您希望以非常动态的方式创建对象时,它基本上是一个有用的工具。我们可以创建一个对象工厂函数,根据接收到的参数创建具有不同原型的对象。
        11
  •  3
  •   edwin    16 年前

    Object.create() 功能。一个解决Crockfords问题并调用init函数的函数。

    这将起作用:

    var userBPrototype = {
        init: function(nameParam) {
            this.name = nameParam;
        },
        sayHello: function() {
            console.log('Hello '+ this.name);
        }
    };
    
    
    function UserB(name) {
        function F() {};
        F.prototype = userBPrototype;
        var f = new F;
        f.init(name);
        return f;
    }
    
    var bob = UserB('bob');
    bob.sayHello();
    

    这里的UserB类似于Object.create,但是根据我们的需要进行了调整。

    如果需要,您也可以拨打:

    var bob = new UserB('bob');
    
        12
  •  3
  •   Vojtech Ruzicka Inv3r53    8 年前

    因为它引起了太多的麻烦。例如,如果不小心,它很容易指向全局对象,这可能会产生非常糟糕的后果。他声称不使用 Object.create不再有意义了。

    https://www.youtube.com/watch?v=PSGEjv3Tqo0

    enter image description here

        13
  •  3
  •   paulyc    7 年前

    new Object.create 服务于不同的目的。 新的 对象.创建 旨在简单地创建一个新对象并设置其原型。为什么这个有用?实现继承而不访问 __proto__ [[Prototype]] 是虚拟机的内部属性,不打算直接访问。唯一可以直接访问 作为 __原型__ 属性是因为它一直是每个主要虚拟机实现ECMAScript的事实上的标准,此时删除它将破坏许多现有代码。

    作为7ochem对上述答案的回应,对象绝对不应该将其原型设置为

    而不是访问 __原型__ 对象.创建 或者之后 Object.setPrototypeOf Object.getPrototypeOf Object.isPrototypeOf .

    而且,作为 Mozilla documentation of Object.setPrototypeOf

    鉴于

    const X = function (v) { this.v = v }; X.prototype.whatAmI = 'X'; X.prototype.getWhatIAm = () => this.whatAmI; X.prototype.getV = () => this.v;

    下面的VM伪代码等价于该语句 const x0 = new X(1);

    const x0 = {}; x0.[[Prototype]] = X.prototype; X.prototype.constructor.call(x0, 1);

    注意尽管构造函数可以返回任何值,但是 语句总是忽略其返回值并返回对新创建对象的引用。

    下面的伪代码等价于 const x1 = Object.create(X.prototype);

    const x0 = {}; x0.[[Prototype]] = X.prototype;

    如你所见,两者之间唯一的区别是 不执行构造函数,构造函数实际上可以返回任何值,但只返回新的对象引用 this 除非另有规定。

    现在,如果我们想用以下定义创建一个子类Y:

    const Y = function(u) { this.u = u; } Y.prototype.whatAmI = 'Y'; Y.prototype.getU = () => this.u;

    然后我们可以像这样通过写入 __原型__

    Y.prototype.__proto__ = X.prototype;

    同样的事情不用写信就可以完成 __原型__ 使用:

    Y.prototype = Object.create(X.prototype); Y.prototype.constructor = Y;

    在后一种情况下,有必要设置原型的构造函数属性,以便原型调用正确的构造函数 new Y 声明,否则 将调用函数 X 新Y 打电话 ,在Y的构造函数中使用 X.call(this, u)

        14
  •  2
  •   p0wdr.com    7 年前

    我喜欢封闭式的方法。

    我仍然使用 new . 我不使用 Object.create 我不使用 this

    我仍然使用 新的 因为我喜欢它的声明性。

    考虑一下这个简单的继承。

    window.Quad = (function() {
    
        function Quad() {
    
            const wheels = 4;
            const drivingWheels = 2;
    
            let motorSize = 0;
    
            function setMotorSize(_) {
                motorSize = _;
            }
    
            function getMotorSize() {
                return motorSize;
            }
    
            function getWheelCount() {
                return wheels;
            }
    
            function getDrivingWheelCount() {
                return drivingWheels;
            }
            return Object.freeze({
                getWheelCount,
                getDrivingWheelCount,
                getMotorSize,
                setMotorSize
            });
        }
    
        return Object.freeze(Quad);
    })();
    
    window.Car4wd = (function() {
    
        function Car4wd() {
            const quad = new Quad();
    
            const spareWheels = 1;
            const extraDrivingWheels = 2;
    
            function getSpareWheelCount() {
                return spareWheels;
            }
    
            function getDrivingWheelCount() {
                return quad.getDrivingWheelCount() + extraDrivingWheels;
            }
    
            return Object.freeze(Object.assign({}, quad, {
                getSpareWheelCount,
                getDrivingWheelCount
            }));
        }
    
        return Object.freeze(Car4wd);
    })();
    
    let myQuad = new Quad();
    let myCar = new Car4wd();
    console.log(myQuad.getWheelCount()); // 4
    console.log(myQuad.getDrivingWheelCount()); // 2
    console.log(myCar.getWheelCount()); // 4
    console.log(myCar.getDrivingWheelCount()); // 4 - The overridden method is called
    console.log(myCar.getSpareWheelCount()); // 1
    

    鼓励反馈。

        15
  •  2
  •   Shardul    6 年前

    new 操作员

    • 这个 新的
    function Car() {
      console.log(this) // this points to myCar
      this.name = "Honda";
    }
    
    var myCar = new Car()
    console.log(myCar) // Car {name: "Honda", constructor: Object}
    console.log(myCar.name) // Honda
    console.log(myCar instanceof Car) // true
    console.log(myCar.constructor) // function Car() {}
    console.log(myCar.constructor === Car) // true
    console.log(typeof myCar) // object
    
    

    对象.创建

    • 你也可以使用 Object.create
    • 但是,它不执行构造函数
    • 对象.创建
    const Car = {
      name: "Honda"
    }
    
    var myCar = Object.create(Car)
    console.log(myCar) // Object {}
    console.log(myCar.name) // Honda
    console.log(myCar instanceof Car) // ERROR
    console.log(myCar.constructor) // Anonymous function object
    console.log(myCar.constructor === Car) // false
    console.log(typeof myCar) // object