假设我有一个构造函数和一些实例方法,比如
function MyClass(name) {
this.name = name || '';
}
MyClass.prototype = {
constructor: MyClass,
isEmptyName: function() {
return this.name === '';
}
}
现在我可以写
var myClass = new MyClass('Ben');
myClass.isEmptyName();
会返回false。现在,如果我再做一个方法,那么还会返回一个布尔值
MyClass.prototype = {
constructor: MyClass,
isEmptyName: function() {
return this.name === '';
}
longerThan: function(len) {
return this.name.length > len;
}
}
我想像这样链接这些方法(不知何故,这就是我的问题:))
myClass.isEmptyName().and.longerThan(2);
现在省略'.and。'部分。我希望上层语句最终返回一个值
false&&是的 - >假
或更现实的样本:
myClass.notEmptyName().and.longerThan(4);
总结我的问题,我会说,我希望我的方法返回一个布尔值,如果它们被称为'直接'myClass.notEmptyName()
应该返回true
,但工作就像我写在样本中,否则。
其他图书馆以某种方式做到这一点,但我无法猜测,npm的should是一个很好的例子:
user.should.have.property('pets').with.lengthOf(4);
user.pets.should.be.instanceof(Array).and.have.lengthOf(4);
由于
答案 0 :(得分:2)
那是不可能的。一个方法不能返回布尔值或者是可链接的,这取决于它以后的使用方式,因为它不知道以后如何使用它。
您可以链接以不同方式验证对象的方法,但如果要在表达式中使用它,则需要通过读取属性或调用方法来获取结果:
function MyClass(name) {
this.name = name;
this.and = this;
}
MyClass.prototype = {
value: true,
isNotEmpty: function() {
this.value = this.value && this.name.length > 0; return this;
},
isLongerThan: function(len) {
this.value = this.value && this.name.length > len; return this;
},
evaluate: function() {
return this.value;
}
};
console.log(new MyClass('Adam').isLongerThan(2).evaluate());
console.log(new MyClass('Bob').isNotEmpty().and.isLongerThan(3).evaluate());
演示:http://jsfiddle.net/Guffa/62e8dLwL/
要允许多次评估,您可以重置evaluate
方法中的值:
evaluate: function() {
var v = this.value;
this.value = true;
return v;
}
答案 1 :(得分:2)
当然,你可以做到。我们将定义一个名为ChainResult
的新中间状态对象,它记住底层对象,当前值和挂起操作(用于组合下一个测试的函数)。我们给这个对象一个valueOf
方法,这样当JS试图将它作为一个原语进行评估时,它看起来就像#34;喜欢它有价值。为了使这项工作,事实证明ChainResult
实际上需要是一个函数,因此我们将必要的属性从函数中挂起。
function ChainResult(obj, val) {
function x() { }
x.obj = obj;
x.val = val;
x.op = null;
// the `valueOf` function spits out the current value when the object is evaluated
x.valueOf = function() { return this.val; };
// the test functions combine the results with the current value
// using the current operation as set by a preceding `and` or `or`
x.isEmptyName = function() {
x.val = x.op(x.val, x.obj._isEmptyName());
return this;
};
x.isLongerThan = function(len) {
x.val = x.op(x.val, x.obj._isLongerThan(len));
return this;
};
// we implement `and` and `or` via getters which set the operation
// on the ChainResult object, and return `this` so we can keep chaining
Object.defineProperties(x, {
and: {
get: function() { x.op = function(a,b) { return a && b; }; return x; }
},
or: {
get: function() { x.op = function(a,b) { return a || b; }; return x; }
}
});
return x;
}
MyClass
定义需要稍微调整一下:
function MyClass(name) {
this.name = name || '';
}
MyClass.prototype = {
constructor: MyClass,
// we implement the testers as pseudo-private functions
_isEmptyName: function() { return this.name === ''; },
_isLongerThan: function(len) { return this.name.length > len; },
// when the public tester functions are invoked directly on the object
// (when they are the first link in the chain), we construct and return a
// ChainResult object with the initial value set correctly
isEmptyName: function() { return ChainResult(this, this._isEmptyName()); },
isLongerThan: function(len) { return ChainResult(this, this._isLongerThan(len)) }
};
流速:
new MyClass('Bob') // create MyClass object
.isEmptyName() // create ChainResult object with value `false`
.or // remember `or` operation in ChainResult object
.isLongerThan(2) // update value of ChainResult object
; // JS tries to convert to scalar, calls valueOf
// true
这需要防弹和收紧,但你明白了。
答案 2 :(得分:1)
我希望我的方法返回一个布尔值,如果它们被称为“直接”
myClass.notEmptyName()
应该返回true
您的方法总是直接在实例上调用,并且总是需要返回一个原始的布尔值。这样,上下文(myClass
)就会丢失,你不能在结果上使用and
方法(或属性获取器)。
我建议你看一下函数式编程,部分应用程序和currying,这对于像这样的流畅接口有很大帮助。给定
function and(fn1, fn2) {
return function(val) {
return fn1(val) && fn2(val);
};
}
function or(fn1, fn2) {
return function(val) {
return fn1(val) || fn2(val);
};
}
function hasEmptyName: function(val) {
return val.name === '';
}
function hasNameLongerThan: function(len) {
return function(val) {
return val.name.length > len;
};
}
你可以写
and(hasEmptyName, hasNameLongerThan(2))(myClass);
然而,使这些函数方法变得复杂。也许是这样的:
function method(name) {
var args = Array.prototype.slice.call(arguments, 1);
return function(instance) {
return instance[name].apply(instance, args);
};
}
Function.prototype.and = function (fn2) {
var fn1 = this;
return function(val) {
return fn1(val) && fn2(val);
};
}
Function.prototype.or = function (fn2) {
var fn1 = this;
return function(val) {
return fn1(val) || fn2(val);
};
}
Object.defineProperty(Object.prototype, "test", function(pred) {
return pred(this);
});
现在你可以写
myClass.test(method("notEmptyName").and(method("longerThan", 4)));
答案 3 :(得分:0)
最后我基于这个帖子中的响应推出了另一个解决方案(谢谢大家!),因为原始问题无法解决,因为javascript运行时无法找到返回值,或返回链接时本身(对象)。解释很乱,对不起:(
查看我的lib,我的方法如下:
check(value)。 isString()等..
最初我想将这些链接起来check(value).isString().and.not.empty()
,但这样,无法完成。 (挑战我)
最后我创建了用于链接的标记,而不是
check(value).isString().and.not.empty()
我可以写
check(value).isstring.and.not.empty.test()
不好,但仍然是。
要查看,请访问github repo上的 checkjs 。 注意: README已过时。
答案 4 :(得分:-2)
如果使用promises,则可以编写返回值并可以链接的函数。请注意,这些都是异步的。
找到这个JS插件:Kris Owal's Q,或者如果你想使用JS库,它们通常包含延迟对象和承诺。