如何摆脱javascript中的绑定情况

时间:2016-04-10 00:04:56

标签: javascript jquery ajax http callback

我有以下代码,我试图用来在按钮数组上注册回调。但我似乎无法理解如何绑定回调中需要的字符串。任何建议将不胜感激!

for (var i = 0; i < this.car_types.length; ++i) {

    this.select_car_buttons.push($("#button_select_car_" +
                this.car_types[i].car_type));

    this.select_car_buttons[this.select_car_buttons.length - 1]
        .click(function() {
            console.log(this.car_types[i].car_type);
    }.bind(this));
}

不知何故,this对象是按钮本身,而不是调用该函数的范围内的对象。

编辑:看起来这个对象确实正确传递了。问题是变量i不会超出范围,而是通过引用而非值来捕获。我该如何解决这个问题?

此外,JavaScript作为一种语言似乎存在很多这样的问题(考虑到传统的C族语言(如C和C ++)使用的语义是正确的,至少可以归类为一个问题)是否有一些问题我可以读到的文章警告我反对这些类型的问题吗?

另一个编辑:尝试使用值捕获的值i进行闭包时,我尝试了以下代码

this.select_car_buttons[this.select_car_buttons.length - 1]
   .click((function(scoped_i) {
      return function() {
            console.log(this.car_types[scoped_i].car_type);
      }.bind(this);                               
}(i)));  

但我在Safari中遇到以下错误

TypeError: undefined is not an object (evaluating 'scoped_i')

编辑:相同的代码适用于Firefox和Chrome,但不适用于Safari!

2 个答案:

答案 0 :(得分:3)

这是一个范围问题。对于现代浏览器(支持ES6 ),您只需在var循环中将let更改为for即可修复。

for (let i = 0; i < this.car_types.length; ++i)

引用MDN docs

  

let 语句声明一个块范围局部变量,可选择将其初始化为一个值。

要获得更多全局支持(非ES6支持),请使用立即调用的函数为变量创建额外的范围(将作为参数传递

this.select_car_buttons[this.select_car_buttons.length - 1]
  .click((function(scoped_i) { // IIF starts here, the new variable is called scoped_i for verbosity
    return function() { // your original function code goes here
      console.log(this.car_types[scoped_i].car_type); // use the newly scoped variable
    }.bind(this);
  }.bind(this)(i))); // end and execute the IIF while passing the i variable to it

答案 1 :(得分:0)

是的,这个结构确实会产生大量的闭包,使代码很难阅读。由于你使用jQuery,有一个更好的方法来解决这个问题,它将数据保存在html中:

HTML:

<button class="select-car" data-car-type="CarA">Select CarA</button>
<button class="select-car" data-car-type="CarB">Select CarB</button>
<!-- And a lot of buttons -->

JS:

var selectCarOnClick = function() {
  console.info($(this).data('car-type'));
};
$('button.select-car').click(selectCarOnClick);

Live exmaple:http://codepen.io/SCLeo/pen/VaQYjW

如果您要存储许多其他信息,并且想要使用对象来存储它们而不是DOM,则可以保存car-name或car-id而不是car-type。

以下是有关$ .data:https://api.jquery.com/jquery.data/

的文档