bind()

bind()

  • ES5 引入了 Function.prototype.bind
  • bind()方法创建一个新的函数,在bind()被调用时,这个新函数的this被bind的第一个参数指定,其余的参数将作为新函数的参数供调用时使用。
  • 也就是说,调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数(someObject)上,无论这个函数是如何被调用的。bind绑定的参数只生效一次。

注意

  1. 函数使用bind()返回的还是一个函数,而call()/apply()则是直接调用函数。
  2. 使用函数声明的方式创建的函数不能使用bind(),只有使用函数表达式的方式创建的函数才能使用。
  3. call()/apply()/bind()都是使用第一个参数改变this的指向。
  4. bind()call()/apply()的传参方法有所不同。

bind()与apply()、call()的共同点

  • 在JS中,这三者都是用来改变函数的this对象的指向的。
  1. 都是用来改变函数的this对象的指向的。
  2. 第一个参数都是this要指向的对象。
  3. 都可以利用后续参数传参
  • 注意:call, apply, bind 都不能改变箭头函数中的this指向
    • 因为箭头函数的this只和定义时的作用域this有关,和调用者/调用环境无关,也永远不会改变

bind()与apply()、call()使用上的区别

无参数情况

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var xw = {
name: "小王",
gender: "男",
age: 24,
say: function () {
alert(this.name + " , " + this.gender + " ,今年" + this.age);
}
}
var xh = {
name: "小红",
gender: "女",
age: 18
}
xw.say(); // 小王 , 男 , 今年24
  • xw的say方法显示xh的数据的几种方法:
    1. xw.say.call(xh);
    2. xw.say.apply(xh);
    3. xw.say.bind(xh)();
      • 如果直接写xw.say.bind(xh)不会有任何结果,call()apply()都是对函数的直接调用,而**bind()返回的仍然是一个函数,因此后面还需要()来进行调用才可以**。

传参情况

1
2
3
4
5
6
7
8
9
10
11
12
13
var xw = {
name : "小王",
gender : "男",
age : 24,
say : function(school,grade) {
alert(this.name + " , " + this.gender + " ,今年" + this.age + " ,在" + school + "上" + grade);
}
}
var xh = {
name : "小红",
gender : "女",
age : 18
}
  • 可以看到say方法多了两个参数,我们通过4种方法进行传参
    1. xw.say.call(xh,"实验小学","六年级");
    2. xw.say.apply(xh,["实验小学","六年级"]);
    3. xw.say.bind(xh,"实验小学","六年级")();
    4. xw.say.bind(xh)("实验小学","六年级");
    • 由于bind()返回的仍然是一个函数,所以我们还可以在调用的时候再进行传参。

react事件绑定函数与bind(this)

在react中,常看到:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
export default class App extends Component {
constructor(props) {/*构造函数,用于实例化对象*/
super(props);
this.foo = this.foo.bind(this);
}

foo() {
// todo something
}

render() {
return (
<View>
<Button onPress={this.foo}/>
</View>
)
}
}
  • **事件绑定处理函数(onPress={this.foo})时,foo方法内部的this的指向就会丢失(此时在foo函数内部打印this得到的是undefined)**。这就会出现外部的foo方法内部的this会丢失指向。
  • 为了解决这个问题,我们在实例化对象的时候就需要在构造函数中绑定thisthis.foo = this.foo.bind(this);),使得无论事件处理函数如何传递,它的this的指向都是固定的,固定指向我们所实例化的对象(App组件)

父组件传递函数给子组件也需绑定

  • 注意:如父组件要传递函数给子组件,则需在父组件构造函数中使用bind绑定该函数this指向
    • 原因:绑定this指向父组件,以免在子组件中使用函数时this指向不是我们所期望的。(比如期望在子组件内通过调用父组件方法来修改父组件的this.state,结果没绑定导致this指向子组件,自然无法修改父组件this.state

react事件绑定函数传参2种情况

父组件绑定this时传参

  • 在React这个例子中,在父组件中使用bind绑定事件函数handleItemDeletethis指向时,如果还想将参数index传入函数,则可在绑定时传入
    1
    2
    // 这个例子里该组件在父组件中调用
    <List.Item onClick={this.handleItemDelete.bind(this, index)}>{item}</List.Item>

父组件绑定this,子组件传参

  • 但如果事件函数和bind绑定都在父组件中,而函数的调用和传参在子组件,就可以这样传参(可参考完整例子):
  1. 父组件的构造函数中使用bind绑定this.handleItemDelete=this.handleItemDelete.bind();
  2. 我们知道bind()返回的还是一个函数,所以在子组件中,我们通过箭头函数在每次调用handleItemDelete()时传入参数index
    1
    2
    // 这个例子里该组件在子组件中调用
    <List.Item onClick={()=>{this.props.handleItemDelete(index)}}>{item}</List.Item>
  • 注意
  1. 在这里不能直接使用handleItemDelete(index)传参是因为handleItemDelete(index)直接执行了函数,而onClick需要绑定的事件函数是不能立即执行的,所以需要新建一个箭头函数让他不立即执行。
  2. **箭头函数是JS表达式,在JSX中需要使用{}**,调用的父组件的函数也是JS表达式,同样中需要使用{}

vue element-ui中自定义form表单rules

  • 基础使用可参考element-ui文档
  • 自定义rules时,我们可以把常用的规则封装到函数validatePositiveNum()内,再将不同的提示语作为this传入封装的函数validatePositiveNum()内,这样就不会干扰到element-ui中自定义rules的校验函数原本传入的参数_rule, value, callback
  • 例子:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // computed内
    rules() {
    // rule, value, callback是校验函数原本自带的传入参数
    const validatePositiveNum = (rule, value, callback) => {
    const reg = /^[+]{0,1}(\d+)$|^[+]{0,1}(\d+\.\d+)$/; // 检验正数
    if (!value) { // value是表单输入值
    callback() // 正常,无提示
    return
    }
    if (!reg.test(value)) {
    const error = this ? new Error(this) : '请输入正数';
    callback(error); // 表单下方出现提示语
    } else {
    callback(); // 正常,无提示
    }
    }
    const rules = {
    weight: [
    // 使用bind就可以在不影响自带传入的那3个参数的前提下,传入提示语
    { validator: validatePositiveNum.bind('重量必须为正数'), trigger: ['change', 'blur'] }
    ],
    }
    return rules
    },