call与apply
call和apply相信很多人用过,或者看源码看到过,在这里简单说说他们之间的关系。首先call和apply都是改变this指向的api。他的区别仅仅只是call和apply的第二位参数起的差别。
代码语言:javascript复制function callTest() { console.log(this); }
function applyTest() { console.log(this); }
const obj = {};
callTest.call(obj, arg1, arg2, arg3...);
applyTest.apply(obj, [arg1, arg2, arg3]);
那么如果有一个问题,call和apply之间,那个性能更高,你会怎么觉得呢?
按照函数的调用方式来说,一般都是采用多个参数传入的方式(arg1,arg2,arg3)。那么实际上call和apply之间,其实是call的性能更好。为什么呢?
其实在底层运行上,apply在调用apply的时候,还需要对传入的第二个参数进行解构赋值。
代码语言:javascript复制applyTest.apply(obj, [arg1, arg2, arg3]);
function apply() {
this.call(obj, [...arguments]);
}
所以从运行的效率的角度上来说,call少了一次解构赋值,运行效率会比apply会更高。
bind原理
我使用bind大概也是因为我用react的缘故。在对组件的onClick绑定事件的时候,往往this的执行是存在问题的,因为我们onClick的事件很多时候是需要调用this.setState的。
代码语言:javascript复制class App extends Component {
constructor() {
this.state = {
text: '1'
}
}
clickHandle() {
this.setState({
text: '2'
})
}
render () {
return (
<div onClick={this.clickHandle}>{this.state.text}</div>
)
}
}
如果我们这样写的话,那么在clickHandle函数中,this的执行就并非App这个class的实例了,而且event对象,这个时候setState就会报错。
如果我们如下修改
代码语言:javascript复制render () {
return (
<div onClick={() => {this.clickHandle()}}>{this.state.text}</div>
)
}
那么这个时候就能正常运行,但是这里会有一个性能问题,当我们足够多的组件的时候,通过这样绑定事件回调是会存在性能问题,因为在每一次render的时候,我们使用箭头函数是一个匿名函数,所以每一次都会重新声明一次函数,导致性能下降,所以这个时候就可以使用bind来解决这个问题了。
代码语言:javascript复制class App extends Component {
constructor() {
this.state = {
text: '1'
}
this.clickHandle = this.clickHandle.bind(this);
}
clickHandle() {
this.setState({
text: '2'
})
}
render () {
return (
<div>OMG-CLI</div>
)
}
}
bind的作用实际就是将当前的函数的this进行绑定,而且放在constructor中进行绑定也是有原因的,因为constructor只会在class初始化的时候执行,所以函数也只需要进行一次绑定就可以了。那么有不少面试题里面都会有叫你使用js来实现bind。其实也很简单。
代码语言:javascript复制Function.prototype.bind = function() {
// 保存当前调用bind的函数指针
const self = this;
// 获取第一个传入参数,你要绑定的this指针
const context = Array.prototype.shift.call(arguments);
// 将传入的参数转为数组
const args = Array.prototype.slice.call(arguments);
// 返回一个函数,通过闭包来保存调用函数的指向,this的指针以及传入的参数
return function() {
self.apply(context, [].concat.call(args, [].slice.call(arguments)));
}
}
所以bind的实现也是相当简单的,只要清楚call和apply以及bind的原理,即可手写一个bind出来。