Using “Object.create” instead of “new”

后端 未结 15 2172
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 06:08

Javascript 1.9.3 / ECMAScript 5 introduces Object.create, which Douglas Crockford amongst others has been advocating for a long time. How do I replace new

15条回答
  •  情话喂你
    2020-11-22 06:46

    Object.create is not yet standard on several browsers, for example IE8, Opera v11.5, Konq 4.3 do not have it. You can use Douglas Crockford's version of Object.create for those browsers but this doesn't include the second 'initialisation object' parameter used in CMS's answer.

    For cross browser code one way to get object initialisation in the meantime is to customise Crockford's Object.create. Here is one 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()
    }
    

    This maintains Crockford prototypal inheritance, and also checks for any init method in the object, then runs it with your parameter(s), like say new man('John','Smith'). Your code then becomes:-

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

    So bob inherits the sayHello method and now has own properties id=1 and name='Bob'. These properties are both writable and enumerable of course. This is also a much simpler way to initialise than for ECMA Object.create especially if you aren't concerned about the writable, enumerable and configurable attributes.

    For initialisation without an init method the following Crockford mod could be used:-

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

    This fills the userB own properties, in the order they are defined, using the Object.gen parameters from left to right after the userB parameter. It uses the for(prop in o) loop so, by ECMA standards, the order of property enumeration cannot be guaranteed the same as the order of property definition. However, several code examples tested on (4) major browsers show they are the same, provided the hasOwnProperty filter is used, and sometimes even if not.

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

    Somewhat simpler I would say than Object.build since userB does not need an init method. Also userB is not specifically a constructor but looks like a normal singleton object. So with this method you can construct and initialise from normal plain objects.

提交回复
热议问题