我正在尝试将函数作用域传递给回调方法。我遇到的问题是我正在获取对象范围,这不让我可以访问原始函数中的参数和局部变量。我对“this”的理解是指当前上下文(无论是窗口还是某个对象)以及本地声明的变量和参数。 [引用 Richard Cornford 在 http://jibbering.com/faq/notes/closures/ 上的出色工作在“执行上下文”部分]。我还知道 JavaScript 中的变量具有函数作用域(如果它们在函数内部声明,则只能从该函数内部访问)。
基于这种理解,在一个新的环境中,我正在尝试编写一个我为我的前雇主做过很多的模式,调用一个异步方法,指定一个回调处理程序并传递我当前的范围,期望它在回调方法。在我当前的环境中,我发现情况并非如此。 (披露:我在以前的环境中使用的是 ExtJS……让我现在觉得我对这个框架有点太自在了,对正在发生的事情做出假设)。
我的简单测试代码演示了我正在尝试做什么以及什么不起作用。
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar); // <- prob: bar undefined
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
lookup();
这里的问题是传递给 MySvcWrap.doWork 的“this”在这种情况下是 Window 全局对象。我的意图是将函数的执行上下文传递给 myHandler。
我试过的。如果我传递的不是“this”,而是一个有效的对象,例如:
function myHandler(data, ctx) {
console.log('myHandler(): this.bar: ' + this.bar); // <- no prob: this.bar
console.log(JSON.stringify(data));
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, {bar: bar}); // scope object is just object
}
我需要有人来解决我的问题...在我的第一个案例中传递“this”时,当然这是全局范围(我在全局定义的函数中)...我的问题是我在传递范围时,我认为我可以在该上下文中访问本地定义的变量和参数......我是否动摇了我以前对 JS 的理解?如何完成这个任务?
最佳答案
顺便说一句,关于代码中范围的几句话:
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, this); // this here points to window object and not to the function scope
}
所以和写是一样的:
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler, window);
}
之所以如此,是因为您在全局范围内定义了查找函数。在 doWork 函数中,当您编写 this 时,它指向 MySvcWrap 对象(因为该函数是在该对象内部定义的)。
如果你的回调函数必须看到 bar 变量,它应该定义在相同的范围内,就像那样
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang',
function (data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
},
this); // scope object is this
}
lookup();
在这种情况下,您将匿名函数作为回调发送,它是在查找函数内部定义的,因此它可以访问其局部变量;我的控制台在这个 cae 中显示了我:
myHandler(): bar: food
{"colors":["red","green"],"name":"Jones","what":"thang"}
为了更容易支持,你可以在查找函数中定义myHandler:
function lookup() {
var bar = 'food'; // local var
var myHandler = function(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
};
MySvcWrap.doWork('thang', myHandler, this); // scope object is this
}
另一方面,为什么一个函数应该访问另一个函数的局部变量?也许可以重新设计...
另一种使您的代码工作的方法是使用匿名函数,而不是查找(如果您只声明并执行该函数一次就可以工作):
(function() {
var bar = 'food';
function myHandler(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
MySvcWrap.doWork('thang', myHandler, this);
}
)();
结果是一样的,但是不再有查找功能了...
还有一个让它工作的想法......实际上你需要在定义 bar 变量的相同范围内定义回调处理程序,所以它可以做得有点棘手,但只是作为替代方案:
function myHandler(bar) { // actually in this case better to call it createHandler
return function(data, ctx) {
console.log('myHandler(): bar: ' + bar);
console.log(JSON.stringify(data));
}
}
MySvcWrap = {
doWork: function(p1, callback, scope) {
var result = {colors: ['red', 'green'], name:'Jones', what: p1};
if (callback) {
callback.call(scope||this,result, scope);
}
}
}
function lookup() {
var bar = 'food'; // local var
MySvcWrap.doWork('thang', myHandler(bar), this); // scope object is this
}
关于 JavaScript 作用域和闭包的阅读资源很少:
关于javascript - 将范围传递给回调函数/绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5044807/
它不等于主线程的binding,这个toplevel作用域是什么?此作用域与主线程中的binding有何不同?>ruby-e'putsTOPLEVEL_BINDING===binding'false 最佳答案 事实是,TOPLEVEL_BINDING始终引用Binding的预定义全局实例,而Kernel#binding创建的新实例>Binding每次封装当前执行上下文。在顶层,它们都包含相同的绑定(bind),但它们不是同一个对象,您无法使用==或===测试它们的绑定(bind)相等性。putsTOPLEVEL_BINDINGput
我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re
请帮助我理解范围运算符...和..之间的区别,作为Ruby中使用的“触发器”。这是PragmaticProgrammersguidetoRuby中的一个示例:a=(11..20).collect{|i|(i%4==0)..(i%3==0)?i:nil}返回:[nil,12,nil,nil,nil,16,17,18,nil,20]还有:a=(11..20).collect{|i|(i%4==0)...(i%3==0)?i:nil}返回:[nil,12,13,14,15,16,17,18,nil,20] 最佳答案 触发器(又名f/f)是
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我正在尝试用ruby中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了
我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我刚刚被困在这个问题上一段时间了。以这个基地为例:moduleTopclassTestendmoduleFooendend稍后,我可以通过这样做在Foo中定义扩展Test的类:moduleTopmoduleFooclassSomeTest但是,如果我尝试通过使用::指定模块来最小化缩进:moduleTop::FooclassFailure这失败了:NameError:uninitializedconstantTop::Foo::Test这是一个错误,还是仅仅是Ruby解析变量名的方式的逻辑结果? 最佳答案 Isthisabug,or
我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法
假设我有这个范围:("aaaaa".."zzzzz")如何在不事先/每次生成整个项目的情况下从范围中获取第N个项目? 最佳答案 一种快速简便的方法:("aaaaa".."zzzzz").first(42).last#==>"aaabp"如果出于某种原因你不得不一遍又一遍地这样做,或者如果你需要避免为前N个元素构建中间数组,你可以这样写:moduleEnumerabledefskip(n)returnto_enum:skip,nunlessblock_given?each_with_indexdo|item,index|yieldit