函数绑定一般采用函数共有父类的原型Function.prototype 上,包括了 call/apply/bind的几个方法,这些方为公有方法。
这几个方法的共同点就是,改变函数执行时的this,同时传入参数并执行函数。
call
其中最为常用的事call方法,其执行步骤为:
- 通过函数类的实例进行调用Function.prototype上的call方法;
- 将调用call的方法函数中的this修改为call的第一个参数;
- 第二个参数开始为向函数实例传递的参数并执行;
代码如下12345678910111213function print() {console.log(this);}var obj = {};obj.printThis = print;print();//windowobj.printThis();//objprint().call(document.body)//this改为dody后执行,控制台输出bodydiv.onclick = function() {print.call(document.body);//绑定事件的this转变}
需要注意的是,严格模式下(use strict),因为ES6默认就是严格模式,所以严格模式用的越来越多:
- call如果传入 null和undefined,this就是null和 undefine;非严格模式下,则为window。
- 同样的,在严格模式下执行window执行函数this为undefined,包括自执行函数和无行为主体的函数执行。
apply
apply与call相似,调用时可以将调用函数的this进行改变并执行调用他的函数。apply的第一个参数与call相同的作用,apply的第二个参数则为一个数组,将数组的每一项作为调用函数的参数,挨个执行。
bind
与call和apply相似,其参数的意义与call相同,只是bind并不会执行函数,而是将更换了this的函数作为返回值,!!!需要注意的是此方法并不兼容所有浏览器
Object.prototype.toString.call
相当于把toString方法中的this修改,Object.prototype.toString 方法会打印出一个‘[object Object]’的字符串,而第二项则为其中的this。
ES7
目前作为ES7的一项提案,函数绑定可以直接采用并排的双冒号(::)来代替,虽然只是提议,但目前Babel转码已经支持。
不添加参数的情况下,“::”的意思同bind相同,如果有参数,则等同于apply
123456foo:: bar;//等同bar.bind(foo);foo::bar(...arguments);//等同于foo.apply(foo,argurments);如果双冒号左边为空,右边为一个对象的方法,则等同于将该方法绑定在该对象上
12345::obj.foo;//等同于obj::obj.foo;//等同于obj.foo.bind(obj);双冒号的返回还是元对象,可采用链式写法
1obj.foo::('p')::('html')