# this

# this 的确定

this 的指向在函数执行的时候确定,不是在定义的时候确定的。

  • 作为普通函数: window
  • 使用 call apply bind:传入什么就绑定什么
  • 作为对象方法被调用:对象本身
  • 在 class 方法中调用:this 就是实例对象
  • 箭头函数:取决于上层作用域的this

这里需要注意的是 setTimeout 中 this 的指向,如果是普通函数,就是 Windows,如果是箭头函数就是他的取决于上层作用域的this

function fn1() {
  console.log(this)
}
fn1() // window
// call 直接调用执行
fn1.call({ x: 100 }) // { x: 100 }
// bind 会返回一个新的函数去执行
const fn2 = fn1.bind({ x: 200 })
fn2() // { x: 200 }


const zhangsan = {
  name: 'zhangsan',
  sayHi() {
    // this 即当前对象
    console.log(this)
  },
  wait() {
    // setTimeout 触发的执行不是对象的方法执行
    setTimeout(function() {
      // this === window
      console.log(this)
    })
  }
}
// 箭头函数的this是取决于上层作用域的this
const lisi = {
  name: 'lisi',
  sayHi() {
    // this 即当前对象
    console.log(this)
  },
  wait() {
    setTimeout(() => {
      // this 即当前对象
      console.log(this)
    })
  }
}

class People {
  constructor(name) {
    this.name = name
    this.age = 20
  }
  sayHi() {
    console.log(this)
  }
}

const wangwu = new People('wangwu')
wangwu.sayHi() // wangwu 对象

# 手写 bind 函数

// 模拟 bind
Function.prototype.bind1 = function() {
  // 将参数拆解为数组
  const args = Array.prototype.slice.call(arguments)
  // 获取 this(数组第一项)
  const t = args.shift()
  // fn1.bind(...)中的 fn1
  const self = this
  // 返回一个函数
  return function() {
    return self.apply(t, args)
  }
}


// 手写 bind 函数
function fn1(a, b, c) {
  console.log('this', this)
  console.log(a, b, c)
  return 'this is fn1'
}
const fn2 = fn1.bind1({ x: 100 }, 10, 20, 30)
const res = fn2()
console.log(res)

# 实例:创建 10 个 a 标签,点击的时候弹出来对应的序号

for (let i = 0; i < 10; i++) {
  let a
  a = document.createElement('a')
  a.innerHTML = i + '<br/>'
  a.addEventListener('click', function (e) {
    e.preventDefault()
    alert(i)
  })
  document.body.appendChild(a)
}

# this 指向

class Person {
  constructor(name) {
    this.name = name
  }
  eat() {
    console.log(`${this.name} eat something`)
  }
}
// 子类
class Student extends Person {
  constructor(name, number) {
    super(name)
    this.number = number
  }
  sayHi() {
    console.log(this.name, this.number)
  }
}
const jie = new Student('jie', 123)
console.log(jie.name) // 'jie'
console.log(jie.__proto__.name) // undefined
// 因为 jie.__proto__.name 的调用 jie.__proto__ 对象没有 name 属性。他的 this 指向的是 jie.__proto__

# new 操作符

new 操作符调用构造函数具体做了有以下:

  • 创建一个新的对象
  • 将构造函数的 this 指向这个新的对象
  • 为这个对象添加属性、方法等
  • 最终返回新的对象

一般使用 new 方法调用构造函数时,构造函数体内的 this 会绑定到新创建的对象上;这里需要注意的是,如果构造函数中显式返回一个值,且返回的是一个对象(返回复杂类型),那么 this 就指向这个返回的对象;如果返回的不是一个对象(返回的是基本类型),那么 this 仍然指向实例。

# this 优先级

显式绑定 this 有:call、apply、bind、new 等操作。对于这些操作符的优先级,new 绑定的优先级比其他显式绑定方法更高;

箭头函数时不能修改其绑定值的。如何区分 new 或者其他显式绑定这两种,可以通过 instanceof 来进行判断

# let、const

这里有个小知识点,使用 let、const 声明的变量不会挂在到 window 全局对象上。 还有一个小细节,函数的 length 属性,用来表示形参的个数。

评 论:

更新: 12/27/2020, 4:59:16 PM