Javascript 使用;对象。创建;而不是",;新";

Javascript 使用;对象。创建;而不是",;新";,javascript,constructor,new-operator,object-create,Javascript,Constructor,New Operator,Object Create,Javascript 1.9.3/ECMAScript 5引入了Object.create,道格拉斯·克罗克福德(Douglas Crockford)和其他人长期以来一直在使用它。如何将下面代码中的new替换为对象。创建 var UserA = function(nameParam) { this.id = MY_GLOBAL.nextId(); this.name = nameParam; } UserA.prototype.sayHello = function() {

Javascript 1.9.3/ECMAScript 5引入了
Object.create
,道格拉斯·克罗克福德(Douglas Crockford)和其他人长期以来一直在使用它。如何将下面代码中的
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();

似乎没有任何优势,所以我想我没有得到它。我可能太新古典主义了。我应该如何使用
Object.create
来创建用户“bob”?

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

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

在您的
userB
示例中,我认为您的
init
方法不应该是公共的,甚至不应该存在,如果您在现有对象实例上再次调用此方法,则
id
name
属性将更改

Object.create
用于使用对象的第二个参数初始化对象属性,例如:

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.create
的第二个参数上初始化,使用与
Object.defineProperties
Object.defineProperty
方法使用的语法类似的对象文本


它允许您设置属性属性(
可枚举的
可写的
,或
可配置的
),这些属性非常有用。

您必须创建一个自定义的
对象。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');

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

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

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()
}
这将维护Crockford原型继承,并检查对象中的任何init方法,然后使用您的参数运行它,如say new man('John','Smith')。然后,您的代码变成:-

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简单得多的初始化方法,特别是当您不关心可写、可枚举和可配置属性时

对于无初始方法的初始化,可使用以下Crockford mod:-

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()
}
这将按照定义的顺序,使用userB参数后从左到右的Object.gen参数填充userB自己的属性。它使用for(prop in o)循环,因此根据ECMA标准,无法保证属性枚举的顺序与属性定义的顺序相同。然而,在(4)个主要浏览器上测试的几个代码示例表明,如果使用hasOwnProperty过滤器,它们是相同的,有时甚至不使用

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并不是一个特定的构造函数,而是一个普通的单例对象。因此,使用此方法,您可以从普通的普通对象构造和初始化。

您可以使
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');

Object.create的另一个可能用法是在中克隆不可变对象

注意:上面的代码片段创建了一个源对象的克隆(也就是不是引用,如cObj=aObj)。它优于复制属性方法(请参见),因为它不复制对象成员属性。相反,它创建另一个目标对象,并在源对象上设置原型。此外,当在dest对象上修改属性时,它们会“动态”创建,屏蔽原型(src)的属性。这是一种快速而有效的克隆不可变对象的方法

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


Fiddle here()(需要Object.create-capable浏览器)。

使用
Object.create(…)
新建对象更有效

提倡这种方法的人通常会说这种方法的优点相当模糊:,或“等等”

然而,我还没有看到一个具体的例子来说明
Object.create
比使用
new
有任何优势。相反,它存在已知的问题

这是因为
Object.create(…)
提倡使用数据创建新对象的做法;在这里,
动物
数据成为
狮子
原型的一部分,并在共享时引发问题。使用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.create(…)
中的可选属性属性,可以使用添加这些属性。

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

在Chromium中,浏览器
new
的速度是
Object.create(obj)
的30倍,尽管两者都非常快。这是非常奇怪的,因为new在Object.create中做了更多的事情(比如调用构造函数),而Object.create应该只是创建一个新对象,将传入的对象作为原型(Crockford中的秘密链接)

也许浏览器有
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!!!
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
proto = new HTMLElement  //fail :(
proto = Object.create( HTMLElement.prototype )  //OK :)
document.registerElement( "custom-element", { prototype: proto } )
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' ]
[ 'James' ]
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
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

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