手写bind,apply,call
手写bind,apply,call
apply,call,bind都是js给函数内置的一些api,调用他们可以为函数指定this的执行,同时也可以传参.
使用方式
//call |
apply和call就是传参不一样,但是两个都是会在调用的时候同时执行调用的函数,但是bind则会返回一个绑定了this的函数.
我们还需要知道一个事情,就是this的指向.
this的指向
this的指向是在函数调用的时候确定下来的,this的指向大致可以分为五种.
1. 默认绑定
默认绑定一般发生在回调函数,函数直接调用
function test() { |
2. 隐式绑定
通俗点说就是谁调用就是指向谁
const obj = { |
3. 显示绑定call,apply,bind
const obj1 = { |
4. new绑定
function Vehicle() { |
5. es6的箭头函数
es6的箭头函数比较特殊,箭头函数this为父作用域的this,不是调用时的this.前四种方式,都是调用时确定,也就是动态的,而箭头函数的this指向是静态的,声明的时候就确定了下来.比较符合js的词法作用域
window.name = 'win' |
5种this的优先级
箭头函数 -> new绑定 -> 显示绑定call/bind/apply -> 隐式绑定 -> 默认绑定
实现apply
- 先给Function原型上扩展个方法并接收2个参数,
Function.prototype.myApply = function (context, args) { |
- 因为不传context的话,this会指向window的,args也做一下容错处理
Function.prototype.myApply = function (context, args) { |
- 需要回想一下绑定this的五种方式,现在要来给调用的函数绑定this了, 这里默认绑定和new肯定用不了,这里就使用隐式绑定去实现显式绑定了
Function.prototype.myApply = function (context, args) { |
- 最后一步要返回函数调用的返回值,并且把context上的属性删了才不会造成影响
Function.prototype.myApply = function (context, args) { |
这样一个简单的apply就实现了,可能会有一些边界问题和错误判断需要完善,这里就不做继续优化了
既然apply实现了,那么call同样也非常简单了,主要就是传参不一样
实现call
//传递参数从一个数组变成逐个传参了,不用...扩展运算符的也可以用arguments代替 |
实现bind
bind和apply的区别在于,bind是返回一个绑定好的函数,apply是直接调用.其实想一想实现也很简单,就是返回一个函数,里面执行了apply上述的操作而已.不过有一个需要判断的点,因为返回新的函数,要考虑到使用new去调用,并且new的优先级比较高,所以需要判断new的调用,还有一个特点就是bind调用的时候可以传参,调用之后生成的新的函数也可以传参,效果是一样的,所以这一块也要做处理 因为上面已经实现了apply,这里就借用一下,实际上不借用就是把代码copy过来
Function.prototype.myBind = function (context, ...args) { |
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 青衣墨客!
评论