2

总之,我发现有 3 种方法可以在 javascript 中声明对象。

var Waffle = {
   tastes:'yummy'
};

var Waffle = function()
{
   this.tastes='yummy';
};

function Waffle() {
   var that = {};
   that.tastes = "yummy";
   return that;
}

第一种方法是Object literal它没有constructor. 我认为下面是相同的方法Object literal

var Waffle = new Object();
Waffle.tastes = 'yummy';

(如果我的理解是错误的。请纠正我。)

我想知道这三种方式的区别是什么。

哪一个是最好的选择?

谢谢。

4

2 回答 2

4

The first is an object literal and is the same as:

var Waffle = new Object();
Waffle.tastes = 'yummy';

which is the same as:

var Waffle = {};
Waffle.tastes = 'yummy';

but of course, their instantiations take multiple lines.

Your second and third examples are functions. Your second example is an expression, while your third example is a declaration. Here's an explanation of their differences: What is the difference between a function expression vs declaration in JavaScript?

Be careful with your second example (the expression), because in order to modify this (correctly), you need to use var waffle = new Waffle();. Since this is an expression, alternatively you could've used a declaration like:

function Waffle() {
    this.tastes='yummy';
}

(to understand the main difference between that and the original, which I don't think affect many people ever, read the link I provided)

The third example is a basic function that returns a new object literal.

As for the best choice...I don't think there's a concrete, definite answer.

Your first example creates a simple, single object. You can add/change properties and methods on it. But it inherits directly from Object. I like to use this when I need one big object for holding many things, and its structure is static. To reuse this, your third example is needed.

Your second example is convenient because you can invoke a new instance, giving the effect of classic OOP...and is the one I normally use. Although the caveat is that you have to use new, otherwise the value of this will be window, which is bad. At the same time, you can modify this prototype and all instances will share it. It also gives you flexibility of having "private" variables, such as:

function Waffle() {
    var testing = 0;
    this.name = "A";
    this.myMethod = function () {
        return testing;
    };
}

Your third example is similar to the second, except that you can't tap into a prototype, since you're returning an Object. It's basically using your first example, but making it reusable. It also allows for "private" variables like above, as well.

So if you're looking for a single object, use your first example. If you're looking for reusability, I'd suggest your second example, while the third is still an example. Hopefully I explained enough about each for you to determine which suits your needs.

于 2013-04-14T07:28:08.727 回答
4

The literal notation and new Object() creates an object whose prototype is directly the Object. Also, properties and methods are attached on the instance.

/*

Object
  A 
  | instance.__proto__
  | 
instance

*/

//all 3 yield the same result

var foo1 = {
  bar : 'bam!'
}

var foo2 = {}
foo2.bar = 'bam!';

var foo3 = new Object();
foo3.bar = 'bam!';

literal

The constructor approach, either the declared function or the assigned function expression approach, has an additional prototype level between the instance and the Object, which contains your prototype functions attached to the constructor's prototype. Anything attached to the constructor's prototype are shared across all instances.

/*

Object 
  A 
  | instance.__proto__.__proto__
  | 
constructor.prototype 
  A
  | instance.__proto__
  |
instance

*/

//these 2 are the same
//bar is attached at the instance

//function expression assigned to variable foo1
var foo1 = function(){
  this.bar = 'bam!'
}

//function declaration named foo2
function foo2(){
  this.bar = 'bam!'
}

//==========================================================================//

//these 2 are the same, but not the same as above
//methods live on the prototype level and are shared across instances

//function expression assigned to variable foo1
var foo1 = function(){}

//function declaration named foo2
function foo2(){}

foo1.prototype.bar = 'bam!'
foo2.prototype.bar = 'bam!'

constructor

The third approach returns a new literal. You don't get the benefits of the constructor method and prototype sharing. It's as if you just called Waffle like an ordinary function, created a literal, attached properties and methods, and returned it.

Best Choice: Depends on purpose.

Object literals:

  • Shorter than new Object and can attach methods/properties upon definition.
  • Properties/methods live on the instance, no running up the prototype chain which means faster look-up.
  • Unoptimized creation of objects might lead to duplicates, which waste memory. For example, creating functions per instance instead of sharing via the prototype.

Constructor:

  • Classical OOP style
  • Inheritance
  • Shared methods via the prototype means less memory used, as opposed to per instance methods.
  • Forgetting the new might have unwanted consequences, like attaching globals (if window is the context)

You can check these out in the Chrome Developer tools. Create them in the Console, and watch these expressions in the Sources tab

于 2013-04-14T07:28:12.463 回答