简体   繁体   English

JavaScript可以进行这种链接吗?

[英]Is this kind of chaining possible in JavaScript?

I'm working on a file manager framework similar to elFinder . 我正在使用类似于elFinder的文件管理器框架。 My current code works fine but now I want to make it look better and add chaining (I'm not sure if it's chaining or decorator pattern). 我当前的代码工作正常,但是现在我想使其看起来更好并添加链接(我不确定它是链接还是装饰器模式)。

Here is a sample of what I want to do: 这是我要执行的操作的示例:

function UI() {}

UI.prototype.folders = function(){
    return [];
}

UI.prototype.folders.prototype.getSelectedFolder = function(){
   return {};
}

Calling UI.folders() should return an array of folder objects. 调用UI.folders()应该返回一个文件夹对象数组。 So if you call UI.folders() you would get something similar to this: 因此,如果调用UI.folders()您将得到类似于以下内容的信息:

[
    Object { name="folder1", selected=false }, 
    Object { name="folder2", selected=false }, 
    Object { name="folder3", selected=true }
]

And calling UI.folders().getSelectedFolder() would filter the results from UI.folders() and will return: 并调用UI.folders().getSelectedFolder()将过滤UI.folders()的结果并返回:

Object { name="folder3", selected=true }

Is this possible? 这可能吗? Is it right to say "chaining" in this case or it's "decorative pattern"? 在这种情况下说“链接”是正确的还是“装饰模式”?
If it's not - is there another more appropriate way to do it? 如果不是,还有其他更合适的方法吗?

Any help wold be really appreciated! 任何帮助将不胜感激!

The code in your question isn't reflective of a proper implementation, but to answer your direct questions, yes, this... 您问题中的代码不能反映正确的实现,但是可以回答您的直接问题,是的,这...

UI.folders().getSelectedFolder()

...would be an example of method chaining. ...将是方法链接的一个例子。


A decorator pattern is different. 装饰器模式不同。 If you have a set of methods, and each one should always first invoke some common function, you can create a decorator that will return a function that first calls the common one, then the actual one... 如果您有一组方法,并且每个方法都应始终先调用某个公共函数,则可以创建一个装饰器,该装饰器将返回一个函数,该函数首先调用公共函数,然后再调用实际函数。

function foo() {
    console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}

function decorateWithFoo(decorated) {
    return function () {
        foo.apply(this, arguments);
        decorated.apply(this, arguments);
    };
}

So you can use decorateWithFoo to create a function that always invokes foo first... 因此,您可以使用decorateWithFoo创建始终首先调用foo的函数。

  // create and decorate bar()
var bar = function(a,b) {
    console.log('I\'m bar, and I was called after "foo", and was given args:', a, b);
};
bar = decorateWithFoo(bar);

bar(123, 456); // this will first call `foo()`, then (the original) `bar()`.

  // create and decorate baz()
var baz = function(a,b) {
    console.log('I\'m baz, and I was called after "foo", and was given args:', a, b);
};
baz = decorateWithFoo(baz);

baz(123, 456); // this will first call `foo()`, then (the original) `baz()`.

Some languages have built in syntax for creating decorators. 一些语言内置了用于创建装饰器的语法。 JavaScript currently does not. JavaScript当前没有。


If you find yourself using decorators in different ways, you could create another function that sets up the initial decorator function... 如果您发现自己以不同的方式使用装饰器,则可以创建另一个函数来设置初始装饰器功能...

function generateDecorator(decorator) {
    return function (decorated) {
        return function () {
            decorator.apply(this, arguments);
            decorated.apply(this, arguments);
        };
    };
}

So our original decoreateWithFoo could have been set up like this... 所以我们原来的decoreateWithFoo可以这样设置...

function foo() {
    console.log('I\'m foo, and I\'m first, and I was given these args:', arguments);
}

var decorateWithFoo = generateDecorator(foo);

To make this work properly, you need to make your folders method be a function that returns an object that inherits from an array.: 为了使它正常工作,您需要使folder方法成为一个函数,该函数返回从数组继承的对象。

UI.prototype.folders = function(){
    // must return an object that inherits from an array
    // that has the additional methods on it you want like getSelectedFolder()
}

The are a few different ways to solve this. 有几种解决此问题的方法。 The primary goal is that when you call a function you get an object/function back that is the same type of object with different properties. 主要目标是,当您调用一个函数时,您将获得一个对象/函数,它是具有不同属性的同一类型的对象。 I'm not a fan of the prototype usage so I would do it like this (this is one way to solve it): 我不喜欢原型用法,所以我会这样做(这是解决它的一种方法):

var FolderList = function ()
{
    var _folders = [];
    folders.pop({ name: "folder1", selected: false });
    folders.pop({ name: "folder2", selected: true });
    folders.pop({ name: "folder3", selected: false });

    // prevent other programers from changing _folders
    // which would break this, so just use a function
    this.folders = function ()
    {
        return _folders;
    }

    this.selectedFolders = function ()
    {
        var tmpFolders = [];
        for (var folderIndex = 0; 
             folderIndex < this._folders.length; 
             folderIndex++)
        {
            if (this._folders[folderIndex].selected)
            {
                tmpFolders.pop(_folders[folderIndex]);
            }
        }
        _folders = tmpFolders;
        return this;
    }

    this.addFolder = function (folder)
    {
        _folders.pop(folder);
        return this;
    }
};

var folderList = new FolderList();
folderList.selectedFolders()
          .addFolder({ name: "folder1", selected: false })
          .addFolder({ name: "folder3", selected: true })
          .selectedFolders();

// array of 2 objects, folder2 and folder3
var arrayOfSelectedFolder = folderList.folders();  

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM