this指向和手写call/apply/bind

84 阅读2分钟

this指向

this本质是一个变量,指向保存在堆中的某个对象的数据

this的指向遵循四个规则,由高到低分别是以下四点

1、new 关键字创建的对象

function Person(name){
    this.name = name;
}
const person = new Person('zs')
console.log(person.name) // zs

this 指向创建的对象

2、用call/apply/bind改变this(显式绑定)

this指向新绑定

3、函数作为对象方法调用(隐式绑定)

this指向该对象

4、其他

this 严格模式为underfined,非严格模式为window

call源码解析

Function.prototype.myCall = function (context, ...args) {
//这里的this是person,参考上面的3
  if (typeof this !== 'function') {
    throw new TypeError('Function.prototype.call - what is trying to be called is not callable');
  }
  const fn = Symbol('fn'); // 创建一个唯一的 Symbol
  context = context || window; // 如果没有传递 context,则默认为全局对象 window
  context[fn] = this; // 将当前函数作为 context 对象的一个属性
  const result = context[fn](...args); // 调用函数,并传递参数列表
  delete context[fn]; // 删除添加的属性
  return result; // 返回函数执行结果
};
function person(a,b,c){
    let name = "ls"
    console.log(this.name,a,b,c)
    return "ok"
}
let zs={name:"zs"}
person.myCall(zs,"test1","test2","test3") //zs test1 test2 test3

改变person的this,this从指向windox改为对象zs

核心是将person变为zs的函数,利用zs取调用,this就变成了zs

apply源码解析

call和apply的区别,call是接收一系列的参数,apply是接收一个数组

Function.prototype.myApply = function (context, args) {
   if (typeof this !== 'function') {
    throw new TypeError('Function.prototype.apply - what is trying to be called is not callable');
  }
  const fn = Symbol('fn'); // 创建一个唯一的 Symbol
  context = context || window; // 如果没有传递 context,则默认为全局对象 window
  context[fn] = this; // 将当前函数作为 context 对象的一个属性
  let result;
  if (args && args.length) {
    result = context[fn](...args); // 如果传递了参数列表,则使用扩展运算符将参数列表展开
  } else {
    result = context[fn](); // 如果没有传递参数列表,则直接调用函数
  }
  delete context[fn]; // 删除添加的属性
  return result; // 返回函数执行结果
};
function person(...args){
    let name = "ls"
    console.log(this.name,...args)
    return "ok"
}
let zs={name:"zs"}
person.myApply(zs,["test1","test2","test3"]) //zs test1 test2 test3

bind源码解析

Function.prototype.myBind = function (context, ...args) {
   if (typeof this !== 'function') {
    throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
  }
  const fn = this; // 当前this为person,是person调用的myBind
  return function(){  //返回一个函数
     return fn.apply(context,args) //改变this指向,并取返回值
  }
};
function person(a,b,c){
    let name = "ls"
    console.log(this.name,a,b,c)
    return "ok"
}
let zs={name:"zs"}
const result = person.myBind(zs,1,2,3) 
result() //zs 1 2 3
console.log(result()) // zs 1 2 3  ok

bind接收的是一系列参数

bind返回是一个函数,需要手动调用