Javascript 一个函数,用于访问任何方法链
我喜欢Ruby的Javascript 一个函数,用于访问任何方法链,javascript,jquery,Javascript,Jquery,我喜欢Ruby的.tap方法的工作方式。它允许您点击任何方法链,而不破坏该链。我允许您操作一个对象,然后返回该对象,这样方法链就可以正常运行。例如,如果您有foo=“foobar”.upcase.reverse,则可以执行以下操作: "foo = foobar".upcase.tap{|s| print s}.reverse 它将打印上格(但不反转)字符串,并像原始行一样继续反转和赋值 我希望在JS中有一个类似的函数,它只用于一个目的:将对象记录到控制台 我试过这个: Object.proto
.tap
方法的工作方式。它允许您点击任何方法链,而不破坏该链。我允许您操作一个对象,然后返回该对象,这样方法链就可以正常运行。例如,如果您有foo=“foobar”.upcase.reverse
,则可以执行以下操作:
"foo = foobar".upcase.tap{|s| print s}.reverse
它将打印上格(但不反转)字符串,并像原始行一样继续反转和赋值
我希望在JS中有一个类似的函数,它只用于一个目的:将对象记录到控制台
我试过这个:
Object.prototype.foo = function() {
console.log(this);
return this;
};
通常,它是有效的(尽管它输出数字对象而不是数字值)
但当我同时使用一些jQuery时,它会中断jQuery并停止页面上所有进一步的代码执行
错误如下:
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
intercept.call(this);
return this;
},
enumerable : false
});
// Usage:
var x = { a:1 };
x.tap(function(){ console.log(this); });
Object.defineProperty(Object.prototype, 'log', {
value : function(){
return this.tap(console.log.bind(console));
},
enumerable : false,
writable : true /* You want to allow objects to overwrite the log method */
});
- 未捕获的TypeError:对象foo没有方法“push”
- 未捕获的TypeError:对象函数(){window.runnerWindow.proxyConsole.log(“foo”);}没有方法“exec”
那么,做我想做的事情的正确方法是什么?将当前对象记录到控制台并返回该对象以便链可以继续的函数。对于原语,它应该记录它们的值,而不仅仅是对象。您正确地理解了如何将方法安全地添加到链中的任何位置,但是您将其添加到Object.prototype是一种侵入性的操作,并且可以很容易地破坏代码。看起来jQuery代码是为您中断的代码 更安全的方法是:
Object.defineProperty(Object.prototype, 'foo', {
value : function() { console.log( "foo" ); return this; },
enumerable : false
});
演示:
最后,一些通用的东西可能是这样的:
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
intercept.call(this);
return this;
},
enumerable : false
});
// Usage:
var x = { a:1 };
x.tap(function(){ console.log(this); });
Object.defineProperty(Object.prototype, 'log', {
value : function(){
return this.tap(console.log.bind(console));
},
enumerable : false,
writable : true /* You want to allow objects to overwrite the log method */
});
至于你问题的原语部分,这有点棘手。当您对原语调用tap方法时,将创建一个对象包装器,并对其调用tap方法。通过对象包装器的valueOf()方法,原语值仍然可用,因此您可以记录它。棘手的是,您无法知道要调用tap方法的“东西”最初是原语还是对象包装器。假设您永远不想使用对象包装器(这是很合理的),您可以使用下面发布的更好的tap方法
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
var val = (this instanceof Number || this instanceof String || this instanceof Boolean) ? this.valueOf() : this;
intercept(val);
return val;
},
enumerable : false
});
var log = console.log.bind(console);
var x = { a : 1 };
x.tap(log);
2.0.tap(log);
请注意,在tap函数的第一个版本中,传递给它的函数在中包含有用的信息,而在第二个版本中,必须将其作为参数传递
如果需要专门的记录器,可以执行以下操作:
Object.defineProperty(Object.prototype, 'tap', {
value : function(intercept) {
intercept.call(this);
return this;
},
enumerable : false
});
// Usage:
var x = { a:1 };
x.tap(function(){ console.log(this); });
Object.defineProperty(Object.prototype, 'log', {
value : function(){
return this.tap(console.log.bind(console));
},
enumerable : false,
writable : true /* You want to allow objects to overwrite the log method */
});
看看这个:嘿@Kostadin,它不适用于任何链,只适用于以“\ux”对象开头的下划线方法链。我知道tap
函数在JavaScript中是一个很大的缺失部分。对于那些寻找Kotlin的作用域函数的人,我发现它们是可用的。谢谢你的详细回答,@Tibos!为了使答案更完美,您能否提供上一个示例的日志版本?我想要一个快速使用的1.log();1.轻敲(记录)代码>变量。此外,我认为在定义该属性之前检查该属性是否未定义是合理的。请注意,1.log
是一个语法错误,您需要1.0.log
。至于已经定义了属性的场景,这是一个我不想触及的大问题。如果覆盖该属性,则依赖于旧行为的代码将中断;如果不覆盖,则依赖于新行为的代码将中断。只有两个实现都有相同的接口,事情才能继续。谢谢你@Tibos,你太棒了!还有一条注释,Object.defineProperty
默认情况下将属性定义为不可枚举,因此enumerable:false
位是多余的。为了清楚起见,我保留它,以表明该属性需要是不可枚举的。