Bind、Call、Apply 理解与应用

我心飞翔 分类:javascript

1. Bind 函数

作用: 返回一个原函数的拷贝,并拥有指定的 this 值和初始参数。

1.1 Bind函数的理解与使用

1.1.1 创建绑定函数的使用

// 创建全局变量
friends = ['glo_zhao', 'glo_dong', 'glo_sun']

const changInfo = {
  name: 'chang',
  friends: ['zhao', 'qian', 'sun', 'li'],
  getOneFri: function () {
    // 返回朋友的随机一位
    const index = Math.floor(Math.random() * this.friends.length)
    return this.friends.slice(index, index + 1)
  }
}
// 函数的测试
console.log(changInfo.getOneFri());
// 返回随机一位chang.friends的值,当前的this指向changInfo

// 创建一个函数
const getRanFri = changInfo.getOneFri;
console.log(getRanFri());
// 返回以为随机的全局变量window.friends的值 , 当前的this执行window

// 创建一个新的角色
const newPerson = {
  friends: ['per_liu', 'per_wang']
}
// 创建一个绑定函数
const bindGetRanFir = getRanFri.bind(newPerson)
console.log(bindGetRanFir());
// 返回一个随机的newPerson的朋友
 

image.png

1.1.2 构造函数的绑定

function Point(x, y) {
  this.x = x
  this.y = y
}
Point.prototype.toString = function () {
  return `(${this.x} ,  ${this.y})`
}
const test = new Point(1, 2)
console.log(test.toString());    // (1 , 2)

const getPoint = Point.bind(null, 3, 4)
const exp = new getPoint()
console.log(exp.toString());    // (3 , 4)
 

image.png

1.2 Bind函数实现原理

if (!Function.prototype.myBind) {
  (function () {    // 立即执行函数
    // const arrayPrototypeSlice = Array.prototype.slice;
    Function.prototype.myBind = function (otherThis) {
      if (typeof this !== 'function') {    // 判断是否是函数调用
        throw new TypeError('Function.prototype.myBind - what is trying to be bound is not callable')
      }
      const _this = this
      const args = [...arguments].slice(1)
      return function F() {
        if (this instanceof F) {      // 判断是否是构造函数的绑定
          return new _this(...args, ...arguments)
        }
        return _this.apply(otherThis, args.concat(...arguments))
      }
    }
  })()
}
 

2. Call函数

作用: call() 方法使用一个指定的 this 值和单独给出的一个或多个参数来调用一个函数。

2.1 Call函数的理解与应用

2.1.1 函数的直接调用

const messsage = 'Hello world'
const point = () => {
  // 通过作用域链,this指向window,message指向全局作用域
  console.log('message is ', messsage);
}
point.call()   // message is Hello world
 

2.1.2 使用call修改this指向

 const obj = {
  messsage: 'obj_message'
}
const point = function () {
  // 通过作用域链,this指向window,message指向全局作用域
  console.log('message is ', this.messsage);
}
point.call(obj)   // message is obj_message
 

2.1.3 通过call函数调用父级构造函数,实现函数的继承

function Father(firstName, lastName) {      // 定义一个father构造函数
  this.lastName = lastName
  this.firstName = firstName
  this.getFamilyName = function () {
    return `${this.lastName} ${this.firstName}`
  }
}

function Child(firstName, father) {       // 定义一个child构造函数
  Father.call(this, firstName, father.lastName)
  this.firstName = firstName    // 重定向一下 名字
}
let zhang_Fa = new Father('san', 'zhang')
let zhang_ch = new Child('liang', zhang_Fa)
console.log(zhang_ch.getFamilyName());      // zhang liang
 

2.2 call函数的实现

if (!Function.prototype.myCall) {
  (function () {
    Function.prototype.myCall = function (context) {
      context = context || window   // 获取到函数的变量
      context.fn = this             // 获取调用者函数
      // point.myCall(obj,arg1,arg2,···) => args = [ arg1···]     // 获取参数
      const args = [...arguments].slice(1)
      // point.myCall(obj,arg1,arg2,···) => obj.fn(arg1,arg2,···)   // 携带返回值的参数执行
      const result = context.fn(...args)
      delete context.fn       // 删除绑定的函数
      return result
    }
  })()
}
 

3. Apply函数

作用: apply() 方法调用一个具有给定this值的函数,以及以一个数组(或类数组对象)的形式提供的参数。

3.1 Apply的实现

apply()的使用方式与call()的方式相似,区别在于函数的参数,apply的参数为数组,call的参数为参数列表

if (!Function.prototype.myApply) {
  (function () {
    Function.prototype.myApply = function (context) {
      context = context || window
      context.fn = this  //  函数绑定
      let result
      if (arguments[1]) {   // 如果存在第二个参数的话
        result = context.fn(...arguments[1])
      } else {
        result = context.fn()
      }
      delete context.fn
      return result
      // const args = [...argumentsr].slice(1)
    }
  })()
}
 

回复

我来回复
  • 暂无回复内容