我应该使用对象文字还是构造函数?


94

我对应该使用javascript创建对象的方式感到困惑。似乎至少有两种方法。一种是使用对象文字符号,而另一种是使用构造函数。有一个相对于另一个的优势吗?


1
最佳答案:stackoverflow.com/questions/4597926/…-总之,您还可以设置一个函数以文字表示法创建实例。每个实例都执行所有方法,而在构造函数中,所有实例都引用原型方法。即构造器具有更好的内存性能。
Federico 2014年

如果内存不是问题,那么对象字面量属性访问的速度要快很多-jsperf.com/module-pattern-vs-object-literal-vs-prototype/4
Daniel Sokolowski

Answers:


131

如果您没有与对象关联的行为(即,如果该对象只是数据/状态的容器),则可以使用对象文字。

var data = {
    foo: 42,
    bar: 43
};

应用KISS原则。如果除了简单的数据容器之外不需要任何其他内容,请使用简单的文字。

如果要向对象添加行为,则可以使用构造函数,并在构造过程中向对象添加方法,或者为类提供原型。

function MyData(foo, bar) {
    this.foo = foo;
    this.bar = bar;

    this.verify = function () {
        return this.foo === this.bar;
    };
}

// or:
MyData.prototype.verify = function () {
    return this.foo === this.bar;
};

这样的类也像数据对象的架构一样工作:您现在(通过构造函数)具有某种约定(通过构造函数),该对象初始化/包含哪些属性。一个自由的文字只是数据的一个无定形的斑点。

您也可能有一个verify作用于普通旧数据对象的外部函数:

var data = {
    foo: 42,
    bar: 43
};

function verify(data) {
    return data.foo === data.bar;
}

但是,这在封装方面是不利的:理想情况下,与实体关联的所有数据和行为都应一起存在。


12
很好的解释,但是如何将函数放在对象文字中呢?我以前看过这个。实际上,下面的帖子中有一个示例。
chobo 2011年

23
如果将函数定义作为对象文字的一部分包括在内,或this.fn = function ...在构造函数中使用该方法,则每个对象实例将具有自己的函数副本。使用原型方法,您只需一次附加每个函数:实例将通过原型继承来继承它们。
Ates Goral

14
我相信你错过了一件重要的事情。只有构造函数才能提供私有成员和公共成员(封装)。在对象字面量中-它们都是公共的。
罗伊·纳米尔

有什么更好的游戏引擎方式?我使用了构造函数方法,但是我的原型无法访问构造函数数据。
zachdyer 2015年

90

本质上可以归结为是否需要对象的多个实例。使用构造函数定义的对象使您可以拥有该对象的多个实例。对象字面量基本上是具有所有公共变量/方法的单例。

// define the objects:
var objLit = {
  x: 0,
  y: 0,
  z: 0,
  add: function () {
    return this.x + this.y + this.z;
  }
};

var ObjCon = function(_x, _y, _z) {
  var x = _x; // private
  var y = _y; // private
  this.z = _z; // public
  this.add = function () {
    return x + y + this.z; // note x, y doesn't need this.
  };
};

// use the objects:
objLit.x = 3; 
objLit.y = 2; 
objLit.z = 1; 
console.log(objLit.add());    

var objConIntance = new ObjCon(5,4,3); // instantiate an objCon
console.log(objConIntance.add());
console.log((new ObjCon(7,8,9)).add()); // another instance of objCon
console.log(objConIntance.add()); // same result, not affected by previous line

1
这是决定时要牢记的一个很好的观点。谢谢。
zkent 2014年

以我的经验,这正是与众不同的原因。很好的例子。
航空

9

以统一方式创建对象的另一种方法是使用返回对象的函数:

function makeObject() {
    var that = {
        thisIsPublic: "a public variable"
        thisIsAlsoPublic: function () {
            alert(that.thisIsPublic);
        }
    };

    var secret = "this is a private variable"

    function secretFunction() { // private method
        secret += "!"; // can manipulate private variables
        that.thisIsPublic = "foo";     
    }

    that.publicMethod = function () {
        secret += "?"; // this method can also mess with private variables
    }

    that.anotherPublicVariable = "baz";

    return that; // this is the object we've constructed
}

makeObject.static = "This can be used to add a static varaible/method";

var bar = makeObject();
bar.publicMethod(); // ok
alert(bar.thisIsPublic); // ok
bar.secretFunction(); // error!
bar.secret // error!

由于JavaScript中的函数是闭包,因此我们可以使用私有变量和方法并避免使用new

来自http://javascript.crockford.com/private.html,有关JavaScript中的私有变量。


7

下面的代码显示了三种创建对象的方法:Object Literal语法,Function Constructor和Object.create()。对象文字语法只是简单地动态创建和对象,因此它__prototype__Object对象,并且可以访问的所有属性和方法Object。从设计模式的角度严格来说,应使用简单的Object文字存储单个数据实例。

函数构造函数具有一个名为的特殊属性.prototype。此属性将成为__prototype__函数构造函数创建的所有对象的属性。添加到.prototype函数构造函数属性中的所有属性和方法将对它创建的所有对象可用。如果您需要数据的多个实例或需要对象的行为,则应使用构造函数。注意,当您要模拟私有/公共开发模式时,最好使用函数构造函数。请记住将所有共享方法放在上,.prototype这样它们就不会在每个对象实例中创建。

创建对象时,Object.create()将对象文字用作__prototype__此方法创建的对象的。通过真正的原型继承,添加到对象文字的所有属性和方法将对从其创建的所有对象可用。这是我的首选方法。

//Object Example

//Simple Object Literal
var mySimpleObj = {
    prop1 : "value",
    prop2 : "value"
}

// Function Constructor
function PersonObjConstr()  {
    var privateProp = "this is private";
    this.firstname = "John";
    this.lastname = "Doe";
}
PersonObjConstr.prototype.greetFullName = function()    {
    return "PersonObjConstr says: Hello " + this.firstname + 
    " " + this.lastname;
};

// Object Literal
var personObjLit = {
    firstname : "John",
    lastname: "Doe",
    greetFullName : function() {
        return "personObjLit says: Hello " + this.firstname +
        ", " + this.lastname;
    }
} 

var newVar = mySimpleObj.prop1;
var newName = new PersonObjConstr();
var newName2 = Object.create(personObjLit);

1
由于您在对象文字内声明了该函数。这是否意味着当您使用Object.create文字内部的函数创建对象时,每个实例将是唯一的?
JohnnyQ

6

这取决于您想做什么。如果要在对象中使用(半)私有变量或函数,则可以使用构造函数。如果您的对象仅包含属性和方法,则可以使用对象文字。

function SomeConstructor(){
    var x = 5;
    this.multiply5 = function(i){
        return x*i;
    }
}
var myObj = new SomeConstructor;

var SomeLiteral = {
    multiply5: function(i){ return i*5; }
}

现在,该方法multiply5myObjSomeLiteral做同样的事情。唯一的区别是myObj使用私有变量。后者在某些情况下可能有用。大多数情况下,Object文字就足够了,并且是创建JS对象的一种好方法。


函数和方法有什么区别?我来自ac#背景,因此对我来说,一个函数是独立的,而一个方法只是属于类的一部分的函数。
chobo 2011年

1
并没有太大的区别,例如参见web-source.net/javascript_tutorial/…。实际上,在DOMscripting(浏览器中的客户端js)中,所有函数都将成为窗口对象(全局命名空间)的方法(您可以将所有“独立”函数都作为window寻址。[somefunction]。)
KooiInc

5

在此处输入图片说明

您是否需要页面对象的单个实例-文字。

您是否只想像DTO对象那样传输数据,简单的GET SET:-文字

您是否要创建具有方法行为,多个实例的真实对象-构造函数,遵循OOP原则,继承:-构造函数。

以下是youtube视频,详细说明了什么是文字,什么是构造函数以及它们之间的区别。

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


1

与对象文字一起使用时,它更加简洁,并且通过引入初始值可以更好地扩展。


如何在对象文字中创建私有变量?
EhevuTov

您可能不是真的,它与原始问题无关,因此我将为您提供一个链接:javascript.crockford.com/private.html
汤姆

1
实际上,这是相关的,因为在存在差异的地方,有理由根据某些情况使用一种或另一种。在这种情况下,您是否要使用私有变量。您可以通过先在文字中创建一个闭包函数来在文字中创建私有变量,但我认为这比较丑陋且难以阅读。
EhevuTov 2013年

我的立场是正确的,我对问题的原始理解是chobo询问如何将变量传递给构造函数,如参数列表与单对象文字参数一样。
汤姆



0

实际上,方法上,我们可以在对象文字中使用私有方法。考虑下面的代码:

var myObject = {

   publicMethod: function () {
      privateMethod1();
      privateMethod2(); 
      function privateMethod1(){
          console.log('i am privateMethod1');
      } 
      function privateMethod2(){
          console.log('i am privateMethod2');
      } 
   }

}

品味的问题,但我更喜欢在可能的情况下使用对象文字。


-1

//对象文字和对象构造函数

function MyData(foo, bar) {
        this.foo = foo;
        this.bar = bar;

    }
MyData.prototype.verify = function () {
        return this.foo === this.bar;
    };

//add property using prototype

var MD  = new MyData;//true.
var MD = new MyData();//true.
MD.verify// return only the function structure.
MD.verify(); //return the verify value and in this case return true coz both value is null. 
var MD1  = new MyData(1,2); // intialized the value at the starting. 
MD1.verify// return only the function structure.
MD1.verify(); // return false coz both value are not same.
MD1.verify(3,3);// return false coz this will not check this value intialized at the top 
MyData.prototype.verify = function (foo,bar) {
    return this.foo === this.bar;
};
var MD1  = new MyData(1,2);
MD1.verify();
MD1.verify(3,3);// return false coz this keyword used with foo and bar that will check parent data 

1
在您的示例中,Object文字在哪里声明?
JohnnyQ '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.