【JavaScript手撕代码】call、apply、bind

修改this指向

方法 参数 返回值 作用
call thisArg, arg1, arg2, ...,注意,call接收的参数是一个参数列表 函数返回值 调用一个函数,将其 this 值设置为提供的值,并为其提供指定的参数。
apply thisArg, [arg1, arg2, ...],请注意这里,apply接收的参数是一个参数数组 函数返回值 调用一个函数,将其 this 值设置为提供的值,并以数组形式为其提供参数。
bind thisArg, arg1, arg2, ... 新函数 创建一个新函数,当调用这个新函数时,它的 this 值被绑定到提供的值,并且它的参数序列前置指定的参数。

可以使用apply()call()方法以新创建的对象为上下文执行构造函数

开始之前,因为这三个都是会改变this的指向,而this指向是js中很重要的一个部分,所以我们停一停,复习一下this指向,以便更好地认识和实现这仨兄贵

this指向

1、构造函数通过new关键字构造对象时, this指向被构造出的对象

 function Game(name, type){
     this.name = name;
     this.type = type;
     Game.prototype.showThis = function(){
         console.log(this)
     }
 }
 var dmc = new Game('DMC', 'ACT')
 dmc.showThis()

【JavaScript手撕代码】call、apply、bind_第1张图片

可以看到指向的是被构造出来的dmc

2、全局作用域中,this指向window

image.png

3、谁调用方法,this指向谁

4、普通函数非通过其他人执行,this指向window

 function fn(){
     console.log(this)
 }
 fn()   //windowfunction fn1(){
     console.log(this)  // window
     function fn2(){
         console.log(this)
     }
     fn2()  // window
 }
 fn1()// 被赋值后再调用
 var obj = {
     fn: function(){
         console.log(this)
     }
 }
 var fn3 = obj.fn
 fn3()   // window

5、数组里面的函数,按照数组索引取出运行时,this指向该数组,其实就是数组调用函数,所以指向数组

 function fn(){
     console.log(this)
 }
 var arr = [fn1]
 arr[0]()  // [fn] --> 就是arr

6、=>函数中的this指向他的父级非=>函数this

callapply都不能改变=>函数的this

以上可以浓缩为:非=>函数的this指向它执行时的上下文对象,=>函数的this指向它的父级非=>函数的this

7、callapplybind可以改变函数运行时候函数中this的指向

节流防抖中可以使用这种方式实现

call

call的主要用途:

  • 直接调用函数
  • 可改变函数内部的this
  • 可以实现继承

使用上面的例子:

  • fn() 相当于 fn.call(null)
  • fn(fn2)相当于fn.call(null, fn2)
  • obj.fn()相当于obj.fn.call(obj)

手写:

 // context - 传入的执行上下文对象, 不传或者传null就默认为window
 // args - 传入的参数列表
 Function.prototype.myCall = function(context, ...args){
     // this只有指向函数才能执行
     if(typeof this != 'function'){
         return new TypeError(`type error! ${this} is not a function`)
     }
     // 获取传入的执行上下文context, 若未传入则指向window, 就是例如fn.call()、fn.call(null)这种
     context = context || globalThis // 使用globalThis是考虑到web和node下的全局this不一样
     // 缓存this到传入的执行上下文对象去执行, 这一步相当于改变了this指向, 即指向了context
     context.fn = this
     // this指向改变后, 传入参数, 原fn在执行上下文对象运行并缓存此时fn在context下运行得到的返回值
     const res = context.fn(...args)
     // 用完就删除执行上下文中新增的this, 取消绑定
     delete context.fn
     // 返回原fn在context下运行得到的返回值
     return res
 }

apply

apply的用途:

  • 调用函数,改变内部的this指向
  • 参数必须为数组
  • 主要应用于数组类
 // apply和call很像,就后面传参有点改动
 Function.prototype.myApply = function(context, args){
     if(typeof this != 'function'){
         return new TypeError(`type error! ${this} is not a function`)
     }
     context = context || globalThis
     context.fn = this
     // 因为传入的是数组, 所以如果没有参数就不要展开传进fn执行
     const res = args ? context.fn(...args) : context.fn()
     delete context.fn
     return res
 }

bind

  • 改变原函数内部指向
  • 返回改变指向后的拷贝

这里因为返回的是拷贝,所以我们要return的是一个function

 Function.prototype.myBind = function(context, ...args1){
     if(typeof context != 'undefined'){
         return new TypeError(`type error! ${this} is not a function`)
     }
     context = context || globalThis
     context.fn = this
     return function(...args2){
         const res = context.fn(...args1, ...args2)
         delete context.fn
         return res
     }
 }

你可能感兴趣的:(手撕JavaScript,javascript,前端,开发语言)