Объект, который возвращает сам экземпляр

Предыстория: Мой последний проект не может использовать большую библиотеку, что меня огорчает. Есть несколько вещей, которые я хотел бы получить из любой библиотеки, такие как отсутствующие функции addClass, hasClass, removeClass, совместимый addEventListener и т.д. Поэтому я создал небольшой объект, который хотел бы получить некоторые мнения в другое время, но я У меня есть небольшие проблемы с настройкой, как я хотел бы.

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

Дано:

 $ = function() {
    this.name = "levi";

    return this;
};

console.log($());

Мы получаем DOMWindow вместо $ из-за необычной природы this в JavaScript. Что более странно для меня, это то, что console.log(new $().name) Name console.log(new $().name) правильно возвращает "levi". Если this связано с окном, почему объект правильно получил значение? Мы могли бы просто добавить новый console.log(new $()) и это работает. Тем не менее, я не хочу писать новое каждый раз. Итак, я попробовал:

$ = function() {
    var obj = function() {
        this.name = "levi";
    };

    return new obj();
};

console.log($());

Что дает мне то, что я хочу, но кажется немного ненужным заключать объект в функцию, которая его создает. Более того, возвращаемый объект - это obj а не $. Сравнительные испытания не пройдут.

Какие еще способы это можно сделать? Есть ли более элегантное решение? У меня нет никаких сомнений по поводу переосмысления всего моего процесса. Я считаю себя довольно хорошим в использовании JavaScript, но создание нового JavaScript - это то, к чему я очень новичок.


Кто-нибудь видит что-то не так со следующим решением?

$a = function() {};

$ = function() {
    if (!(this instanceof $)) {
        return new $();
    }

    this.name = "levi";

    return this;
};

//helper function
var log = function(message) {
    document.write((message ? message : '') + "<br/>");
};

log("$().name == window.name: " + ($().name == window.name)); //false
log("$().name: " + $().name); //levi
log("window.name: " + window.name); //result

log();

log("$a instanceof $: " + ($a instanceof $)); //false
log("typeof $a: " + (typeof $a)); //function
log("typeof $: " + (typeof $)); //function

Кажется, он работает во всех моих тестах.

Ответ 1

Самый простой способ сделать то, что вы хотите, будет (я думаю):

$ = function(){
    if (!(this instanceof $)){
     return new $;
    }
    this.name = 'levi'; 
    return this;
}

Тот факт, что просто возвращение this не создает экземпляр из $, связано с тем, что метод this создается как $ как регулярная функция: в этом случае значение this указывает на глобальный объект (в браузере: window, фактически вызов выполнения $() совпадает с window.$()). Это факт жизни javascript, так сказать. Тот факт, что console.log(new $().name) показывает правильное значение, состоит в том, что вы вызываете функцию как конструктор, который возвращает экземпляр этого конструктора (т.е. Новый экземпляр $). Но console.log($().name) также будет печатать 'levi', потому что он возвращает глобальный объект с свойством name, т.е. window.name. попробуйте $(); console.log(name), и теперь вы увидите, что name является глобальной переменной. Поэтому, если вы не хотите использовать ключевое слово new каждый раз, проверьте, вызвана ли ваша функция как регулярная функция или как конструктор для экземпляра (=== instanceof $) внутри функции конструктора. С помощью вышеупомянутого метода конструктор экземпляров, независимо от того, был ли он создан с помощью или без new, всегда будет $

Возможно, вам нужно перефразировать заголовок вашего вопроса: "Объект [конструктор], который возвращает экземпляр самого себя

Возможно, эта запись в блоге может пролить дополнительный свет.

Ответ 2

Способ jQuery - это первые тесты, если this есть window (называемый как функция), и если да, то возвращает новый экземпляр самого себя. Например:

var $ = function() {
    if(this === window) {
        return new $();
    }
    this.name = "levi";
    return this;
};

console.log($());

Это работает, потому что, когда вы обычно вызываете функцию (func()), this будет таким же, как и вызывающий this. (Связанный, но не несущественный: obj.method() будет иметь this be obj) Поскольку область по умолчанию window, this внутри $ будет window, когда вы называете ее $().

Когда вы вызываете функцию с помощью new, происходит следующее: JavaScript создает новый объект, а затем вызывает вашу функцию с this, установленным для этого объекта.

Это решение работает, потому что оно сначала проверяет, есть ли this window, и поэтому он был вызван как $(). Если он был вызван как $(), он вернет new $(). В противном случае он был вызван с помощью new $() и будет работать как ожидалось.

Ответ 3

>  $ = function() {
>     this.name = "levi";
> 
>     return this; };
> 
> console.log($());

Мы получаем DOMWindow вместо $

Когда вы вызываете $как funciton, тогда это ключевое слово задается глобальным объектом, как это было бы для любой функции, называемой так.

из-за причудливой природы этого в JavaScript

Javascript это ключевое слово * работает так, как указано для работы. Он отличается от других языков, но так оно и работает.

Что более странно для меня, console.log($(). name) правильно возвращает "Levi".

Когда вы вызываете $как функцию, его это ключевое слово является глобальным объектом, поэтому:

this.name = 'levi';

создает свойство глобального объекта с именем name со значением 'levi'. Не странно, когда вы знаете, что происходит.: -)

Мы могли бы просто добавить новый console.log(новый $()), и он работает.

Так предполагается, что конструкторы должны быть вызваны в javascript. Когда функция вызывается с именем new, ее это ключевое слово устанавливается на новый объект, поэтому this.name создаст новое свойство этого объекта. Кстати, return this избыточен, конструкторы возвращают это по умолчанию.

> $ = function() {
>     var obj = function() {
>         this.name = "levi";
>     };
> 
>     return new obj(); };

console.log($()); Что дает мне то, что Я хочу, но кажется немного ненужным для обертывания объекта внутри которая создает его. В дальнейшем более того, это тип obj, а не тип $

Предположительно вы используете typeof, который может возвращать только одно из значений, указанных ECMA-262. Этот короткий список (который включает в себя объект, число, строку и так далее) не включает $.

Какими другими способами это может быть сделано?

Вы можете использовать найденный вами подход, клон Лассе Рейхштейна Нильсена (также популяризированный Дубосом Крокфордом как "порожденный" ) и образцом модуля Ричарда Корнфорда. Используйте Google, есть много, много сообщений обо всех вышеперечисленных.

Ответ 4

Попробуйте что-то вроде этого:

function $(name){
    if( !(this instanceof arguments.callee) ){
        return new arguments.callee(name);
    }
    this.name = name;
    return this;
}

Обновить:

@Леви Моррисон

Изменить: кто-нибудь видит что-то не так в следующем решении:

С тех пор как вы спросили: Я не совсем влюблен в document.write.
Вместо этого попробуйте:

var log = function(message){
    if(message){
        document.body.appendChild(document.createTextNode(message));
    }
    document.body.appendChild(document.createElement('br'));
}