js的this、bind、call、apply个人领悟

this

1.非箭头函数:

  • 如果是该函数是一个构造函数,this指针指向一个新的对象

  • 在严格模式下的函数调用下,this指向undefined

  • 如果是该函数是一个对象的方法,则它的this指针指向这个对象

2.箭头函数:

  • 箭头函数不会创建自己的this,它只会从自己的作用域链的上一层继承this

总结:普通函数的this指向看调用,箭头函数的this指向看声明,指向声明时候的函数作用域;
setTimeout会延迟函数的声明

bind、call、apply

  1. bind
  • 绑定this不执行(执行时绑定this一次,可新生成函数储存持久型this绑定)
  1. call
  • 绑定this执行n参数任意类型(执行时绑定this一次)
  1. apply
  • 绑定this执行第二个参数必须数组分解依次执行(执行时绑定this一次)

apply实践

var person = {
  fullName: function(city, country) {
    return this.firstName + " " + this.lastName + "," + city + "," + country;
  }
}
var person1 = {
  firstName:"John",
  lastName: "Doe"
}
person.fullName.apply(person1, ["Oslo", "Norway"]);//数组内传入前面函数的参数
"John Doe,Oslo,Norway"

this和call结合运用


let a,
  barObj = { msg: "bar的this指向" };
fooObj = { msg: "foo的this指向" };
function foo() {
  a(); // 结果:{ msg: 'bar的this指向' }
}
function bar() {//箭头函数this绑定在这层(bar)
  a = () => {
    console.log(this); //箭头函数作用域局限于bar
  }; // 在bar输出当前this信息
}
bar.call(barObj); // 改变bar指向barobj执行后 a:输出this的函数
a(); //(当前a输出bar)
foo.call(fooObj); // 将foo的this指向fooObj
/// a为箭头函数输出{msg: "bar的this指向"}
/// a为不箭头函数输出最外层(windows或者其他)

箭头函数和普通函数差异

普通函数的this指哪打哪,箭头函数较特殊在创建的时候就已定死(除非后续再赋值可以改变),图中

function bar() {//箭头函数this绑定在这层(bar)
  a = () => {
    console.log(this); //箭头函数作用域局限于bar
  }; // 在bar输出当前this信息
}
bar.call(barObj)

箭头函数是赋值给了a,由bar调用(谁调用bar就指定死了this,箭头函数this绑定在这个“谁”上),所以这里是bar.call(barObj),绑定在barObj

箭头函数的this没有绑定b对象成功,貌似永远绑定了barObj(这是箭头函数第一次绑定的地方,后续也没由修改,要修改只能重新赋值a=()=>{console.log(this)}类似这样)

其实自己刚入门的时候就已熟读this指向问题了,但是在综合运用场景或者复杂运用场景才正宗明白如何使用this,所谓实践出真知,工作中一班也不会频繁更改this指向,一般也就一次(初始化的时候),所以很少实践这种场景,coding后对自己提升蛮大的💪。

call 源码实现


// eslint-disable-next-line no-extend-native
Function.prototype.myCall = function(content) {
  content.fn = this
  let args = []
  for (let i = 1; i < arguments.length; i++) {
    args.push(`arguments[${i}]`)
  }
  // eslint-disable-next-line no-eval
  let result = eval(`content.fn(${args})`)
  delete content.fn
  return result
}

function a() {
  console.log(arguments)
}
a.myCall({ d: 1 }, 2, 's', [1, 2, 3], { s: 1 }, function() {})

aplly 源码实现

// eslint-disable-next-line no-extend-native
Function.prototype.myApply = function(content) {
  content.fn = this
  let args = []
  for (let i = 1; i < arguments.length; i++) {
    args.push(`arguments[${i}]`)
  }
  // eslint-disable-next-line no-eval
  let result = eval(`content.fn(${args})`)
  delete content.fn
  return result
}

function a() {
  console.log(arguments)
  console.log(arguments.length)
  console.log(arguments[0])
}
a.myApply({ d: 1 }, [2, 's', [1, 2, 3], { s: 1 }, function() {}])

bind 源码实现


// eslint-disable-next-line no-extend-native
Function.prototype.myBind = function(content) {
  content.fn = this
  let args = []
  for (let i = 1; i < arguments.length; i++) {
    args.push(`arguments[${i}]`)
  }
  let result = (...resultArgs) => {
    for (let i = 0; i < resultArgs.length; i++) {
      args.push(`resultArgs[${i}]`)
    }
    // eslint-disable-next-line no-eval
    eval(`content.fn(${args})`)
  }
  return result
}

function a() {
  console.log(arguments)
}

let newFunc = a.myBind({ d: 1 }, 2, 's', [1, 2, 3], { s: 1 }, function() {})

newFunc('aaa', { tt: 'you' })

posted @ 2019-11-15 15:54  霜末之冬  阅读(191)  评论(0编辑  收藏  举报