this

83 阅读2分钟

1.前言

this的指向和在哪里定义无关,跟如何调用有关

2.绑定原则

1.默认绑定

/**
 * 独立函数调用
 * 浏览器环境指向window,严格模式下为undefined
 */
function f() {
  console.log(this) // window
}
f()

2.隐式绑定

/**
 * 注:箭头函数需区别对待
 */
const p1 = {
  name: "a",
  getName() {
    console.log(this.name) // a
    console.log(this) // p1
  },
}

p1.getName()
/**
 * 隐式丢失-普通
 */

const p1 = {
  age: "a",
  getName() {
    console.log(this.age) // undefined
    console.log(this) // window
  },
}

const f = p1.getName
f()
/**
 * 隐式丢失-进阶
 */

var age = 18
const p1 = {
  age: 38,
  getAge() {
    console.log(this.age)
    console.log(this)
  },
}

function fn(func) {
  func()
}
fn(p1.getAge) // 18,window

3.显式绑定

/**
 * 显式绑定:call/apply/bind
 */
/**
 * call
 *
 * 用法:call(指向对象,..arg)
 */

var name = "a"
const p1 = {
  name: "b",
  getName(sex) {
    console.log(this.name)
    console.log(sex)
    console.log(this)
  },
}

function init(fn) {
  fn.call(p1, "man")
}

init(p1.getName) // b,man
/**
 * apply
 *
 * 用法:apply(指向对象,arg)
 */

var name = "a"
const p1 = {
  name: "b",
  getName(sex) {
    console.log(this.name)
    console.log(sex)
    console.log(this)
  },
}

function init(fn) {
  fn.apply(p1, ["man"])
}

init(p1.getName) // b,man
/**
 * bind
 *
 * 用法:传入this,返回一个绑定后的函数
 *
 * 注:调用bind时可以传参,返回后的函数也可以传参
 */

var name = "a"
const p1 = {
  name: "b",
  getName(sex) {
    console.log(this.name)
    console.log(sex)
    console.log(this)
  },
}

function init(fn) {
  const newFn = fn.bind(p1)
  newFn("man")
}

init(p1.getName) // b,man

4,new关键字

/**
 * new
 *
 * new调用时,this就指向实例对象
 */

function Person(nm) {
  this.nm = nm
}

const p1 = new Person("a")
console.log(p1)

3.绑定优先级

/**
 * 1,隐式绑定 > 默认绑定
 */

function getNm() {
  console.log(this.nm)
}
const p1 = {
  nm: "a",
  getNm,
}
p1.getNm()
/**
 * 2,显式绑定 > 隐式绑定
 */

var nm = "b"
const p1 = {
  nm: "a",
  getNm() {
    console.log(nm)
  },
}

p1.getNm.call(this) // b
p1.getNm.apply(this)
p1.getNm.bind(this)()
/**
 * 3,bind > call/apply
 */
var nm = "b"
const p1 = {
  nm: "a",
  getNm() {
    console.log(nm)
  },
}

const newFn = p1.getNm.bind(this) // b

newFn.call(p1) // 仍旧为b
newFn.apply(p1) // 仍旧为b
/**
 * new > bind
 *
 * 注:new不能和call比较,Person.call is not a constructor
 */

const p = {
  age: 1,
}

function Person(nm, age) {
  this.nm = nm
  this.age = age
}

// const p1 = new Person.call(p, "A")
// console.log(p1) // Person.call is not a constructor

const newFn = Person.bind(p)
const p2 = new newFn("p2", 5)
console.log(p2) // Person { nm: 'p2', age: 5 },不受bind影响

4.箭头函数

/**
 * 1,箭头函数不绑定this,它的this指向上一层作用域
 */

var nm = "window"
const p1 = {
  nm: "p1",
  getName: () => {
    console.log(this.nm)
  },
}
p1.getName() // window
/**
 * 2,进阶:应用场景
 *
 * 在getName2中通过this拿到p2中的nm,即p2
 */

// 方法一
// const p2 = {
//   nm: "p2",
//   getName() {
//     let _this = this

//     return {
//       nm: "p3",
//       getName2() {
//         console.log(this)
//         console.log(_this.nm)
//       },
//     }
//   },
// }
// const res = p2.getName()
// res.getName2()

// 方法二
const p2 = {
  nm: "p2",
  getName() {
    return {
      nm: "p3",
      getName2: () => {
        console.log(this)
        console.log(this.nm)
      },
    }
  },
}
const res = p2.getName()
res.getName2()

5,总结

/**
 * 4种绑定规则:默认,隐式,显示,new绑定
 *
 * 优先级:new > bind > call/apply > 隐式 >默认
 */