用javascript链接方法

时间:2016-01-20 11:24:50

标签: javascript method-chaining

我正在尝试使用类似于jquery的javascript方法创建链接。请告诉我如何使用javascript实现链接。

var controller = {
    currentUser: '',
    fnFormatUserName: function(user) {
        this.currentUser = user;
        return this.currentUser.toUpperCase();
    },
    fnCreateUserId: function() {
        return this.currentUser + Math.random();
    }
}
var output = controller.fnFormatUserName('Manju').fnCreateUserId();

3 个答案:

答案 0 :(得分:1)

正如我已经解释的那样,因为你从fnFormatUserName返回一个字符串,所以你不能用它来链接。

要启用链接,您需要返回调用方法的对象。因此,您不能使用getter方法进行链接。

在你的例子中,处理它的方法是让getter方法和方法更新可用于链接的对象,如



var controller = {
  currentUser: '',
  fnFormatUserName: function(user) {
    this.currentUser = user.toUpperCase();
    return this;
  },
  fnCreateUserId: function() {
    this.userId = this.currentUser + Math.random();
    return this;
  },
  getUserId: function() {
    return this.userId;
  }
}
var output = controller.fnFormatUserName('Manju').fnCreateUserId().getUserId();
document.body.innerHTML = output;




另一个版本可能是



var controller = {
  currentUser: '',
  fnFormatUserName: function(user) {
    if (arguments.length == 0) {
      return this.currentUser;
    } else {
      this.currentUser = user.toUpperCase();
      return this;
    }
  },
  fnCreateUserId: function() {
    this.userId = this.currentUser + Math.random();
    return this;
  },
  getUserId: function() {
    return this.userId;
  }
}
var output = controller.fnFormatUserName('Manju').fnCreateUserId().getUserId();
r1.innerHTML = output;
r2.innerHTML = controller.fnFormatUserName();

<div id="r1"></div>
<div id="r2"></div>
&#13;
&#13;
&#13;

答案 1 :(得分:0)

您可以使用 proxies 来修饰方法,以便它们返回对象本身(“this”)而不是实际的方法返回值。下面是一个 chainer 函数的实现,它可以对任何对象执行此操作。代码还声明了一个特殊符号“目标”,可用于访问原始对象(和未更改的方法返回值),丢弃链接代理。

const target = Symbol('Symbol for the target of the chainer proxy');
const targetSymbol = target;
const chainer = (target) =>
  new Proxy(target, {
    get: (_, prop, receiver) =>
      prop === targetSymbol
        ? target
        : typeof target[prop] === 'function'
        ? new Proxy(target[prop], {
            apply: (f, _, args) => {
              f.apply(target, args);
              return receiver;
            },
          })
        : target[prop],
  });

const controller = {
    currentUser: '',
    fnFormatUserName: function(user) {
        return this.currentUser = user.toUpperCase();
    },
    fnCreateUserId: function() {
        return this.currentUser + Math.random();
    }
}


const output = chainer(controller).fnFormatUserName('Manju')[target].fnCreateUserId();

console.log(output);

另一种选择是装饰方法将始终返回具有两个属性的中间对象:this 上下文(“this”)和对具有未装饰方法的原始对象的引用(“target”)。见下文。

const chainer = (target) =>
  new Proxy(target, {
    get: (_, prop, receiver) =>
        typeof target[prop] === 'function'
        ? new Proxy(target[prop], {
            apply: (f, _, args) => {
              f.apply(target, args);
              return {
                this: receiver,
                target,
              }
            },
          })
        : target[prop],
  });

const counter = {
  value: 0,
  increment: function() { 
    return ++this.value;
  }
}

const value = chainer(counter)
    .increment().this
    .increment().target
    .increment();

console.log(value);

答案 2 :(得分:0)

我想这可能会被视为“作弊”,但您可以很容易地通过扩展 String.prototype 获得类似的结果,例如:

String.prototype.upper=function(){return this.toUpperCase()};
String.prototype.makeId=function(){return this+Math.random()};

// test

const str="abc";

console.log(str.upper().makeId(), str);

当然,它会改变当前会话中所有字符串的行为,因为它们现在将具有与其关联的附加方法 .upper().makeId()