【问题标题】:Using Object.create() the correct way以正确的方式使用 Object.create()
【发布时间】:2014-07-05 18:50:39
【问题描述】:

学习 Javascript 我正在寻找不同的方法来创建对象。似乎前进的方向是使用Object.create()

很难找到关于使用 Object.create() 的最佳实践的可靠答案,因为即使是特定的 Object.create() 文章似乎也略有不同。

我想做的是用自己封装的数据创建多个对象。

我喜欢使用封装,似乎对我有用的是

function Foo() {
    var message = "Hello";

    return {
        bar:bar
    }

    function bar(){ 
        return message; 
    }
}

World = (function(){ 
    var obj = Foo();
    var tank = Object.create(obj);

    return {
        baz:baz
    }

    function baz(){ 
        alert(tank.bar()); 
    }

})();

运行World.baz() 按预期工作,但我仍然不确定我是否正确。

所有答案将不胜感激,谢谢。

【问题讨论】:

  • Foo() 已经返回了一个对象,为什么还要使用Object.create
  • 如果我想用自己封装的数据创建多个对象
  • 基于Foo()返回的对象?
  • 是的,作为射击游戏的特定坦克。使用 Object.create(Foo) 似乎不起作用(起初看起来应该是合乎逻辑的)。当我调用 World.baz() 时,我得到未定义的函数
  • 敢问 tank = {}; 有什么问题吗?

标签: javascript ecmascript-5 ecmascript-6


【解决方案1】:

通常在 javascript 中你想像这样创建对象:

var obj = {};
obj.someProperty = 'someValue';
obj.someOtherProperty = 'someOtherValue';

或者,您可以使用对象字面量表示法,如下所示:

var obj = {
    someProperty: 'someValue',
    someOtherProperty: 'someOtherValue'
};

Object.create 函数是一个有趣的函数。是的,它确实创建了一个空对象,但它不像上面定义的对象。使用 Object.create 实例化和对象将赋予新的空对象继承,直至您为 Object.create 函数提供的参数。例如,如果我们将一个对象定义为:

var actions = {
    shout: function(message){
        console.log(message.toUpperCase() + '!');
    }
}

然后用 Object.create() 创建一个新对象:

var newObject = Object.create(actions);  // creates a new object: newObject = {};

newObject 将不包含任何它自己的属性,但它可以访问父操作对象的属性。定义这些对象后,试试这个:

newObject.hasOwnProperty('shout');    // returns false
newObject.shout('Hello!');    // logs 'HELLO!!'

这个例子只是为了展示继承是如何从新创建的对象到它的父对象的。这可能非常有用,但请确保在使用 Object.create 创建对象之前特别需要该行为 - 否则,最好是安全的并使用上述其他两种方法之一。

希望有帮助!

编辑:

或者,如果您只是想为同一个对象创建多个单独的实例,您可以创建一个构造函数并使用 new 关键字调用它,如下所示:

var Tank = function(speed, durability){
    this.speed = speed;
    this.durability = durability;
    this.location = 0;
    this.shoot = function(){
        console.log('Pew pew');
    };
    this.move = function(){
        this.location += speed;
    };
}

var myTank = new Tank(5, 15);    // creates new tank with speed 5 and durability 15,
                                 // that also has all the default properties and methods,
                                 // like location, shoot, and move.

var yourTank = new Tank(7, 12);  // instantiates a different tank that myTank, with it's
                                 // own speed and durability properties, but also has the
                                 // default location, shoot, and move properties/ methods

var enemyTank = new Tank(10, 25);// instantiates yet another, unique tank with it's own 
                                 // unique values for speed and durability, but again with
                                 // the default location, shoot, and move properties/methods

【讨论】:

  • 我不能从 obj 外部访问对象成员 'someProperty' 吗?
  • 'someProperty' 存在于 obj 对象上。您可以使用点表示法从该对象外部访问它:obj.someProperty。对于不是函数的对象的属性,它们存在于该对象上并没有太大区别。但是,在函数的情况下,函数所依赖的对象经常会影响函数的行为方式,尤其是由于关键字“this”。
【解决方案2】:

尝试这种方法来创建封装数据的 javaScript 对象。如您所见,每个 Foo 实例都有自己的属性和状态。

    var Foo = function() {

        var Foo = function Foo(customMessage) {
            this.message = customMessage || "Hello";
        }

        Foo.prototype.message;

        Foo.prototype.bar = function(){ 
            return this.message; 
        }

        return Foo;
    }();

    var tank1 = new Foo();
    var tank2 = new Foo("Goodbye");

    alert(tank1.bar());
    alert(tank2.bar());

【讨论】:

    【解决方案3】:

    我建议使用构造函数来封装数据。如果您真的需要使用Object.create(),则需要使用Object.create() 创建一个构造函数原型系统。但是,无论如何,您只是在World.baz() 方法中从Foo() 的结果调用.bar()。这并不意味着World 应该指向Foo() 的结果。

    Object.prototype.__construct = function() {
        //This is the default constructor from any new object. We change it to change the constructor of objects as we go along. We could make no __construct method on Object.prototype because it doesn't do anything, so we're not going to call it, but we're going to define it anyway since we want all objects to have a __construct method, even if they don't define a new one on top of the default.
    };
    //Object.prototype is our default object. We add methods to object to change the prototype of objects as we go along.
    
    var Foo = {}; //Any object that doesn't inherit from anything must inherit from Object.prototype. We do this by just setting it to {} (or new Object()).
    //If we're going to define a new constructor, we need to call it _after_ we've defined it.
    Foo.__construct = function() {
        var message = "Hello!";
        this.bar = function() {
            return message;
        }
    };
    Foo.__construct();
    Foo.bar() //returns "Hello!"
    //Note that message is encapsulated and _cannot_ be accessed through Foo itself.
    
    var World = {}; //World _does not_ point to Foo. It simply calls a method of Foo in one of its methods.
    World.__construct = function() {
        //Now, if the method of Foo we're going to call in the method of World is going to alter Foo, then we should make a copy of Foo using Object.create(). The method we're going to call isn't _actually_ going to alter Foo, but it's good practice to make a copy because it _could_ if we made it so.
        var obj = Object.create(Foo);
        //Because Foo has been constructed and obj is a copy of Foo, we don't need to construct obj. We only need to construct an object if we define a new constructor property.
        this.baz = function() {
            alert(obj.bar());
        };
    };
    World.__construct();
    World.baz() //alerts "Hello!"
    //Note that obj is encapsulated within World. obj points to Foo, but again, World _does not_ point to Foo.
    

    【讨论】:

    • Noble 我最初确实使用了新的。我不鼓励使用 new 并被告知要使用 Object.create() ,它不像 new 那样直观,而且它也给我带来了对象没有自己的局部变量的问题,这是我得到时会跨越的桥梁到
    • 那么你需要基于Object.create()创建一个构造函数系统。我编辑了我的答案以显示这一点。
    • @Aaron 谁告诉你不要使用 new 的?关于如何以及为何使用构造函数、原型和 Object.create 的一些示例可以在这里找到。stackoverflow.com/questions/16063394/…
    猜你喜欢
    • 2019-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-08
    相关资源
    最近更新 更多