igCircle Blog

call bind apply的区别以及源码的手写

2025年8月6日

5分钟阅读

2 次浏览

0 条评论

前端三大件

标签

js手写

call方法的第一个参数也是this的指向,后面传入的是一个参数列表改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次 当第一个参数为null、undefined的时候,默认指向window(在浏览器中) `js function fn(...args) { console.log(this的指向为${this}, args) } let obj = { ...

call

call方法的第一个参数也是this的指向,后面传入的是一个参数列表改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

当第一个参数为nullundefined的时候,默认指向window(在浏览器中)

js
1function fn(...args) {
2 console.log(`this的指向为${this}`, args)
3}
4let obj = {
5 myName: '张三',
6}
7
8fn.call(obj, 1, 2) // this会变成传入的obj,传入的参数是一个参数列表;
9fn(1, 2) // this指向window
10fn.call(null, [1, 2]) // this指向window
11fn.call(undefined, [1, 2]) // this指向window

apply

apply接受两个参数,第一个参数是this的指向,第二个参数是函数接受的参数,以数组的形式传入

改变this指向后原函数会立即执行,且此方法只是临时改变this指向一次

当第一个参数为nullundefined的时候,默认指向window(在浏览器中)

js
1function fn(...args) {
2 console.log(`this的指向为${this}`, args)
3}
4let obj = {
5 myName: '张三',
6}
7
8fn.apply(obj, [1, 2]) // this会变成传入的obj,传入的参数必须是一个数组;
9fn(1, 2) // this指向window
10fn.apply(null, [1, 2]) // this指向window
11fn.apply(undefined, [1, 2]) // this指向window

bind

bind 方法和 call 很相似,第一参数也是this的指向,后面传入的也是一个参数列表(但是这个参数列表可以分多次传入)

改变this指向后不会立即执行,而是返回一个永久改变this指向的函数

JS
1function fn(...args){
2    console.log(`this的指向为${this}`,args);
3}
4let obj = {
5    myName:"张三"
6}
7
8const bindFn = fn.bind(obj,[1,2]); // this 会变成传入的obj ,bind不是立即执行
9bindFn(1,2) // this指向obj
10fn(1,2) // this指向window

手写 apply

  • 判断是否为 undefined 或 null,如果是,则 this 指向的是 window
  • 给目标对象创建一个属性,将要调用的方法绑定到这个属性上
  • 用 arguments 拿到传入的参数
  • 直接运行刚刚创建的属性
  • 删除这个属性
js
1Function.prototype.myApply = function(context) {
2 if (typeof context === 'undefined' || context === null) {
3  context = window
4 }
5
6 context.fn = this //this指向的是apply方法的函数
7 let args = arguments[1] //拿到第一个参数
8 let result
9 if (args) {
10  result = context.fn(...args) //运行一下
11 } else {
12  result = context.fn()
13 }
14 delete context.fn
15 return result
16}

手写 call

思路同 apply 基本相同

不一样的是要通过 arguments 取出除第一位之外的所有参数放到一个数组里,然后通过展开运算符给要执行的函数或方法传参

js
1//往Function的原型对象上加myCall方法
2Function.prototype.myCall = function(context) {
3 //判断是否为undefined或null
4 if (typeof context === 'undefined' || context === null) {
5  context = window
6 }
7 context.fn = this //给目标对象新建一个属性,绑定这个函数
8 let args = [...arguments].slice(1) //过arguments取出除第一位之外的所有参数放到一个数组
9 let result = context.fn(...args) ////运行一下
10 delete context.fn //删除目标对象上的fn属性
11 return result
12}

手写 bind

bind() 方法会创建一个新函数。 当这个新函数被调用时,bind() 的第一个参数将作为它运行时的 this, 之后的一序列参数将会在传递的实参前传入作为它的参数

要注意因为 bind 转换后的函数可以作为构造函数使用,此时 this 应该指向构造出的实例

js
1Function.prototype.myBind = function(context) {
2 if (typeof this !== 'function') {
3  throw new TypeError('error')
4 }
5 // 获取参数
6 const args = [...arguments].slice(1)
7 let _this = this
8 return function fn() {
9  //判断是都被当做构造函数使用,根据调用方式,传入不同绑定值
10  return _this.apply(
11   this instanceof fn ? new fn(...arguments) : context,
12   args.concat(...arguments)
13  )
14 }
15}

小结

  • 三者都可以改变函数的 this 指向
  • 三者的第一个参数都是 this 要指向的对象,如果没有这个参数,或者参数为 undefined 或 null,则默认会指向全局 window
  • 三者都可以传参,apply 接受的是数组,call 和 bind 接收的是参数列表,bind 的参数列表可以分为多次传入
  • apply 和 call 是立即执行,而 bind 是返回绑定后的那个 this 之后的函数

参考文章

喜欢这篇文章吗?

加载中...

评论

0

登录后即可参与评论讨论

加载评论中...

相关文章

深入理解JS闭包的9大使用场景

深入理解 JS 闭包的 9 大使用场景,包括返回值、函数赋值、迭代器等

前端三大件
jsES6

2025-05-11

2

0

目录