在JavaScript中,var thing和function thing()有什么区别?

11

我只是想知道JavaScript对象声明的以下两种方式之间的区别。具体来说,是指thing对象文字和来自thing类的thing1对象之间的区别。

代码:

var thing = {
    sanity:0,
    init:function(){
        //code
    },
    send:function(){
        //code
    }
}

function thing(){
    this.sanity = 0;
    this.init = function(){
        //code
    };
    this.send = function(){
        //code
    };
}

thing1 = new thing();
5个回答

23

静态对象/对象字面量

静态对象或对象字面量不需要使用new运算符进行实例化,同时表现为单例模式。考虑以下示例:

代码:

var staticObject1 = {
 a: 123,
 b: 456
};
var staticObject2 = staticObject1;
console.log(staticObject1, staticObject2);
staticObject2.b = "hats";
console.log(staticObject1, staticObject2);

输出:

Object a=123 b=456  Object a=123 b=456
Object a=123 b=hats Object a=123 b=hats

需要注意的是,改变 staticObject2.b 也会影响到 staticObject1.b。然而,这可能并不总是期望的效果。像 Dojo 这样的许多库提供了对象克隆方法,如果您想复制静态对象,则可以缓解这种情况。继续上面的例子,请考虑以下代码:

Code:

var staticObject3 = dojo.clone(staticObject1); // See the doc in the link above
staticObject1.a = "pants";
console.log(staticObject1, staticObject2, staticObject3);

输出:

Object a=pants b=hats Object a=pants b=hats Object a=123 b=hats
注意,staticObject1staticObject2的成员值相同,而staticObject3不受这些其他对象的更改影响。
静态对象还可用于创建项目或库名称空间,而不是填充全局范围,并促进了兼容性。
在创建需要可移植性或互操作性的库时,这非常有用。这可以在流行的库中看到,例如Dojo、YUI和ExtJs,在这些库中,所有或大多数方法都被称为dojo.examplMethod()YUI().exampleMethod()Ext.exampleMethod()
静态对象也可以被认为是类似于C/C++中结构体的松散类比。

类构造函数/实例化对象

JavaScript中的类基于原型继承,这是一个更复杂的主题,可以在这里这里这里阅读有关内容。
与静态对象相反,这种对象创建方法提供了利用JavaScript闭包属性的私有作用域对象成员和方法的独特机会。请考虑以下私有类成员的示例: 代码:
var SomeObject = function() {
    var privateMember = "I am a private member";
    this.publicMember = "I am a public member";

    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
};

var o = new SomeObject();
console.log(typeof o.privateMember, typeof o.publicMember);
o.publicMethod();

输出:

undefined string
I am a private member I am a public member

注意,typeof o.privateMember的值为"undefined"且无法在对象外部访问,但在对象内部可以访问。

私有方法也可以实现,但不像公有方法那么简单直接。问题在于私有方法中this的值默认为window,因此必须应用两种技术之一来确保this指向我们正在处理的对象,即SomeObject的实例。考虑以下示例:

代码:

var SomeObject = function() {
    var privateMember = "I am a private member";
    var privateMethod = function() {
        console.log(this.publicMember);
    };

    this.publicMember = "I am a public member";
    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
    this.privateMethodWrapper = function() {
        privateMethod.call(this);
    }
};

var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();

输出:

undefined function function
I am a public member

请注意,在 privateMethodWrapper() 中,使用 call 并传递 this 作为函数的上下文来执行 privatemethod。这是可以接受的;然而,下面的技术更可取(在我的意见中),因为它简化了调用范围并产生相同的结果。前面的示例可以更改为以下内容:

代码:

var SomeObject = function() {
    var self          = this;
    var privateMember = "I am a private member";
    var privateMethod = function() {
        console.log(self.publicMember);
    };

    this.publicMember = "I am a public member";
    this.publicMethod = function() {
        console.log(privateMember, this.publicMember);
    };
    this.privateMethodWrapper = function() {
        privateMethod();
    }
};

var o = new SomeObject();
console.log(typeof o.privateMethod, typeof o.publicMethod, typeof o.privateMethodWrapper);
o.privateMethodWrapper();

输出:

undefined function function
I am a public member

这个答案是我在博客中发布的一篇文章的基础,其中我提供了更多的例子。希望能帮到你 ;)


这个语句中的数字不应该翻转吗?“注意,更改staticObject1.b也会影响staticObject2.b。” - Rani Kheir
确实应该这样做。已修复! - Justin Johnson

6

案例2引用了JavaScript类构造函数。一个明显的区别是,变量还不是一个对象,因此您无法在内部引用thing1.sanity。您需要通过创建所述类的实例来初始化该类,然后才能调用任何内部成员:

var myConstructor = function() {
    this.sanity = 0;
}

// wont work
alert(myConstructor.sanity);

// works
var thing1 = new myConstructor();
alert(thing1.sanity);

这里有一篇文章,比我的简单例子更深入地探讨了以下内容:

类构造函数与对象字面量


1

区别在于thing1对象与thing1类相关联,并将继承(不是字面意义上的)thing1原型。

例如,您可以稍后编写

thing.prototype.initAndSend = function() { this.init(); this.send(); };

你将能够编写 thing1.initAndSend() 而不需要修改 thing1。此外,thing1.constructor 将等于 thing 方法,而 {}.constructor 等于 Object
顺便说一下,标准惯例是大写类名。

0

使用第一种方法,您正在声明单个对象。而使用第二种方法,则是在声明一个类,从该类中您可以实例化(即创建)许多不同的副本。


0

函数是对象,也是构造函数(可以使用new实例化它们)。

哈希表/对象({})无法被实例化,因此它们通常用作数据结构。我不确定将它们称为“对象”是否明智。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接