В чем разница между var thing и function thing () в JavaScript? - PullRequest
11 голосов
/ 10 ноября 2009

Мне было просто интересно узнать разницу между следующим объявлением объектов JavaScript. В частности, отличие литерала вещи-объекта от объекта вещи от класса вещи.

Код:

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 ]

22 голосов
/ 10 ноября 2009

Статические объекты / Литералы объектов

Статические объекты или литералы объектов не требуют создания экземпляра с помощью оператора 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 , предлагают метод клонирования объектов, который может облегчить эту ситуацию, если вы хотите сделать копию статического объекта. Продолжая предыдущий пример, рассмотрим следующее:

Код:

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

Обратите внимание, что значения элементов staticObject1 и staticObject2 одинаковы, тогда как staticObject3 не подвержены изменениям этих других объектов.

Статические объекты также полезны для создания пространств имен проектов или библиотек, вместо того, чтобы заполнять глобальную область, и обеспечивают совместимость, как никто другой.

Это полезно при создании библиотек, которые требуют переносимости или совместимости. Это можно увидеть в популярных библиотеках, таких как Dojo, YUI и ExtJs, где все или большинство методов называются dojo.examplMethod(), YUI().exampleMethod() или Ext.exampleMethod() соответственно.

Статические объекты также можно считать слабо аналогичными struct в C / C ++.

Классовые Конструкторы / Созданные Объекты

Классы в JavaScript основаны на прототипном наследовании, которое является гораздо более сложным предметом и может быть прочитано о здесь , здесь и здесь .

В отличие от статических объектов, этот метод создания объекта предоставляет уникальную возможность для членов и методов объекта частной области действия из-за свойства closuer 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 "неопределен" и недоступен снаружи объекта, но находится изнутри.

Также можно создавать частные методы, но они не так просты, но все же просты в реализации. Проблема заключается в том, что значение 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(), privatemethod было выполнено с использованием call и передачей this для контекста функции. Это все хорошо; однако следующая техника предпочтительна (на мой взгляд), поскольку она упрощает область вызова и дает идентичные результаты. Предыдущий пример можно изменить на следующий:

Код:

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

Этот ответ послужил основой для поста в моем блоге , где я привожу дополнительные примеры. Надеюсь, это поможет;)

6 голосов
/ 10 ноября 2009

Случай 2 ссылается на javascript конструкторы класса . Очевидное отличие состоит в том, что переменная еще не является объектом, поэтому вы не можете внутренне ссылаться на thing1.sanity. Вам придется инициализировать класс, создав экземпляр указанного класса перед вызовом любых внутренних членов:

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

// wont work
alert(myConstructor.sanity);

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

Вот статья, углубленная в мой быстрый пример:

Конструкторы классов и литералы объектов

1 голос
/ 10 ноября 2009

Разница в том, что объект thing1 связан с классом thing1 и наследует (не буквально) прототип thing1.

Например, позже вы можете написать

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

После этого вы сможете написать thing1.initAndSend() без изменения thing1. Кроме того, thing1.constructor будет равно методу thing, тогда как {}.constructor равно Object.

Кстати, стандартное соглашение состоит в том, чтобы использовать имена классов с большой буквы.

0 голосов
/ 10 ноября 2009

Функции - это объекты, а также конструкторы (вы можете создавать их экземпляры, используя new).

Хеш-таблицы / объекты ({}) не могут быть созданы, поэтому они обычно используются в качестве структур данных. И я не уверен, разумно ли называть их «объектами».

0 голосов
/ 10 ноября 2009

При первом способе вы объявляете один объект. Со вторым вы объявляете класс, из которого вы можете создать экземпляр (т.е. создать) много разных копий.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...