Как работает базовая цепочка объектов/функций в javascript?

Я пытаюсь понять принципы создания цепочки функций в стиле jQuery прямо у себя в голове. Под этим я подразумеваю:

var e = f1('test').f2().f3();

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

Что я знаю:

  1. Функции должны возвращать сами себя, то есть «вернуть это»;
  2. Цепные функции должны находиться в родительской функции, то есть в jQuery, .css() является подметодом jQuery(), следовательно, jQuery().css();
  3. Родительская функция должна либо возвращать себя, либо новый экземпляр самой себя.

Этот пример работал:

var one = function(num){
    this.oldnum = num;

    this.add = function(){
        this.oldnum++;
        return this;
    }

    if(this instanceof one){
        return this.one;    
    }else{
        return new one(num);    
    }
}
var test = one(1).add().add();

Но это не так:

var gmap = function(){

    this.add = function(){
        alert('add');

        return this;    
    }   

    if(this instanceof gmap) {
        return this.gmap;   
    } else{
        return new gmap();  
    }

}
var test = gmap.add();

person Geuis    schedule 08.07.2009    source источник
comment
Функции не возвращают сами себя, они возвращают объект, который поддерживает методы, которые вы используете в цепочке. В случае с jQuery это работающий узел.   -  person drudru    schedule 08.07.2009
comment
Каждая функция должна заканчиваться на return this;.   -  person Marc B    schedule 10.06.2012
comment
Чтобы сделать существующие методы цепочками, вы можете попробовать следующее: stackoverflow.com/a/15797662/162793   -  person sheldonh    schedule 05.04.2013
comment
связанные: как работает цепочка jquery?   -  person Bergi    schedule 11.06.2014


Ответы (5)


В JavaScript функции являются объектами первого класса. Когда вы определяете функцию, она является конструктором для этого функционального объекта. Другими словами:

var gmap = function() {
    this.add = function() {
        alert('add');
    return this;
    }

    this.del = function() {
       alert('delete');
       return this;
    }

    if (this instanceof gmap) {
        return this.gmap;
    } else {
        return new gmap();
    }
}
var test = new gmap();
test.add().del();

By assigning the

new gmap();
to the variable test you have now constructed a new object that "inherits" all the properties and methods from the gmap() constructor (class). If you run the snippet above you will see an alert for "add" and "delete".

В приведенных выше примерах «это» относится к объекту окна, если вы не переносите функции в другую функцию или объект.

Поначалу мне сложно понять цепочку, по крайней мере, это было для меня, но как только я понял это, я понял, насколько мощным инструментом это может быть.

person Lark    schedule 08.07.2009
comment
Я думаю, вы можете удалить if ... else ..., для меня это не имеет особого смысла. Функции конструктора возвращают this по умолчанию, или вы можете вернуть его явно. Я считаю, что this.gmap будет неопределенным, а new gmap() зациклит функцию конструктора навсегда, поэтому я не знаю, почему это работает для OP. - person Jose V; 26.06.2020

К сожалению, прямой ответ должен быть «нет». Даже если вы можете переопределить существующие методы (что вы, вероятно, можете во многих UA, но я подозреваю, что не в IE), вы все равно застрянете с неприятными переименованиями:

HTMLElement.prototype.setAttribute = function(attr) { 
    HTMLElement.prototype.setAttribute(attr) //uh-oh;  
}

Лучшее, что вам может сойти с рук, это использовать другое имя:

HTMLElement.prototype.setAttr = function(attr) {
    HTMLElement.prototype.setAttribute(attr);
    return this;
}
person kojiro    schedule 10.06.2012
comment
Похоже, я буду придерживаться jQuery для цепочки! - person Derek 朕會功夫; 10.06.2012
comment
Обратите внимание, что этот ответ относится к другому вопросу. - person kojiro; 15.06.2012

Чтобы «переписать» функцию, но по-прежнему иметь возможность использовать исходную версию, вы должны сначала присвоить исходную функцию другой переменной. Предположим, пример объекта:

function MyObject() { };

MyObject.prototype.func1 = function(a, b) { };

Чтобы переписать func1 для цепочки, сделайте следующее:

MyObject.prototype.std_func1 = MyObject.prototype.func1;
MyObject.prototype.func1 = function(a, b) {
    this.std_func1(a, b);
    return this;
};

Вот рабочий пример. Вам просто нужно использовать эту технику на всех стандартных объектах, которые, по вашему мнению, нуждаются в цепочке.

К тому времени, когда вы проделаете всю эту работу, вы, возможно, поймете, что есть лучшие способы выполнить то, что вы пытаетесь сделать, например, использовать библиотеку, в которую уже встроена цепочка. *cough* jQuery *кашляет*

person FishBasketGordo    schedule 10.06.2012

Во-первых, позвольте мне заявить, что я объясняю это своими словами.

Цепочка методов в значительной степени вызывает метод объекта, возвращаемого другой функцией/методом. например (используя jquery):

$('#demo');

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

$('#demo').text('Some Text');

Таким образом, пока функция/метод возвращает объект, вы можете связать метод возвращаемого объекта с исходным оператором.

Что касается того, почему последние не работают, обратите внимание на то, где и когда используется ключевое слово this. Скорее всего, это проблема контекста. Когда вы вызываете this, убедитесь, что this относится к самому объекту функции, а не к объекту окна/глобальной области.

Надеюсь, это поможет.

person ryanwaite28    schedule 16.03.2017

Просто вызовите метод как var test = gmap().add();

поскольку gmap - это функция, а не переменная

person Shankar Us    schedule 19.11.2014
comment
Это не сработает, потому что add не определено на gmap(), а только на new gmap(). - person Artjom B.; 19.11.2014