这种链接在JavaScript中可能吗?

问题描述:

我正在研究类似于elFinder的文件管理器框架。我目前的代码工作正常,但现在我想让它看起来更好,并添加链接(我不知道它是链或装饰模式)。
这种链接在JavaScript中可能吗?

这里是什么,我想做一个示例:

function UI() {} 

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

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

调用UI.folders()应该返回文件夹对象的数组。所以,如果你UI.folders()你会得到一些与此类似:

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

,并呼吁UI.folders().getSelectedFolder()将过滤从UI.folders()结果将返回:

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

这可能吗?在这种情况下说“链接”还是“装饰模式”是正确的?
如果不是 - 是否有另一种更合适的方法来做到这一点?

任何帮助将真正感激!

+1

你没有正确地进行继承。 '... folders.prototype.getSelectedFolder'没有任何好处,因为'UI.prototype.folders'只返回一个普通数组。为'folders.prototype'产生效果,你需要调用'folders'作为构造函数,并让它返回被构造的对象而不是Array。 – 2012-04-15 17:25:42

+1

...但是,正确实施,'UI.folders()。getSelectedFolder()'是方法链接的一个例子。 – 2012-04-15 17:26:43

+1

+1我不确定为什么投票反对,这不仅仅是一个很好的描述性问题,而且还包括了你想要做的事情。 – 2012-04-15 17:32:25

这是几种不同的方法来解决这个问题。主要目标是当你调用一个函数时,你会得到一个对象/函数,它是具有不同属性的相同类型的对象。我不是原型用法的粉丝,所以我会这样做(这是解决它的一种方式):

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(); 
+0

感谢您的代码!使用你的代码的一部分我想出来:) – tftd 2012-04-16 22:37:54

为了使这个正常工作,你需要让你的文件夹,方法是返回,从一个数组:继承对象的功能

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

在你的问题中的代码是不能反映一个适当的实施,但回答你的直接问题,是的,这...

UI.folders().getSelectedFolder() 

...将是一个方法链的例子。


装饰模式是不同的。如果你有一组方法,每个人应该总是先调用一些常用的功能,你可以创建一个装饰,将返回首先调用常见的一种,那么实际的一个功能...

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); 
    }; 
} 

所以,你可以使用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()`. 

一些语言已经建立了用于创建装饰器的语法。 JavaScript目前没有。


如果你发现自己使用的装饰以不同的方式,你可以创建,设置了最初的装饰功能的其他功能...

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

所以我们原来decoreateWithFoo可能已经建立了这样的...

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

var decorateWithFoo = generateDecorator(foo); 
+0

感谢您的扩展解释 - 它清除了一切! – tftd 2012-04-16 22:43:57