this指针

38 阅读2分钟

执行域

var a = "123"
function test1() {
    var a = '345'
    test2()        // 先在test2 上下文查找,后在父级作用域查找
}
function test2() { // 父级作用域在外层
    console.log(a)
}
test2() // '123'

// 问题2:
function foo() {
  var a = b = 10 //  => 
  // var a = 10
  // b = 10
}
foo()
console.log(b) // 10
console.log(a) // Error: a is not defined

this绑定规则: 与调用方式相关,与定义方式无关

// 1. 默认绑定(独立调用函数)
function foo1() {
  console.log(this)
}
foo1() // window

// 2. 隐式绑定: 有.绑定
function test() {
    console.log(this)
}
const obj = {
  a: "name",
  b: test
}
obj.b()

// 3. 显示绑定: call, apply, bind
function foo1() {console.log(this)}
foo.bind("abc").call("efg") // String "abc" : bind优先级更高

// 4. new 绑定

// 优先级: new > 显式 > 隐式 > 默认
// 1. 显式 > 隐式
function foo() {
  console.log(this)
}

const obj = {
  name: 'obj',
  foo: foo.bind("aaa")
}
obj.foo() // String "aaa"

// 2. new 大于隐式
const obj = {
  name: "obj",
  foo: function() {
    console.log(this)
  }
}

const res = new obj.foo() // foo {}

// 3. new > 显式
function foo3() {
  console.log(this)
}
const bar3 = foo3.bind("aaa")
const obj3 = new bar3() // foo {}

this特殊处理

function foo() {
  console.log(this)
}
// 1. 绑定为全局
foo.apply(null)
foo.apply(undefined)

// 2. 间接绑定
const obj1 = {
  name: "obj1",
  foo: function() {
    console.log(this.name)
  }
}

const obj2 = {
  name : "obj2"
}
obj2.bar = obj1.foo
obj2.bar();              // "obj2"
(obj2.baf)()             // "obj2"
(obj2.bar = obj1.foo)() // 独立引用: window.name -> undefined

箭头函数

// 箭头函数不绑定this, 即向上级作用域查找
const obj = {
  data: [],
  getData: function() {
    const _this = this
    setTimeout(function() {
      // _this.data => []
      console.log(this.data) // window.data : undefined
    })

    setTimeout(() => {
      console.log(this.data) // obj.data : []
    })
  }
}
obj.getData()

this面试题

面试题1

// var 声明在 GO 或 AO 对象中
var name = 'window'
var person1 = {
  name: 'person1',
  foo1: function() {
    console.log(this.name)
  },
  foo2: () => console.log(this.name),
  foo3: function() {
    return function() {
      console.log(this.name)
    }
  },
  foo4: function() {
    console.log(this) // 看该函数如何调用
    return () => {
      console.log(this.name)
    }
  }
}
var person2 = {name: 'person2'}

person1.foo1()             // person1(隐式绑定)
person1.foo1.call(person2) // person2(显示绑定优先级大于隐式绑定)

person1.foo2()  // window (不绑定作用域,上层作用域是全局)
person1.foo2.call(person2) // window

person1.foo3()()  // window(独立函数调用)
person1.foo3.call(person2)() // window
person1.foo3().call(person2 ) // person2

person1.foo4()() // person1(箭头函数不绑定this, 上层作用域是person1)
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1(箭头函数不绑定this, 上层作用域是person1)

面试题2

var name = "window"

function Person(name) {
  this.name = name
  this.foo1 = function() {
    consol.elog(this.name)
  }

  this.foo2 = () => console.log(this.name)  
  this.foo3 = function() {
    return function() {
      console.log(this.name)
    }
  }
  this.foo4 = function () {
    return () => {
      console.log(this.name)
    }
  }
}

var person1 = new Person("person1")
var person2 = new Person("person2")

person1.foo1()  // person1
person1.foo1.call(person2) // person2

// obj内部不是上层作用域,而函数调用栈中是作用域
person1.foo2()  //  person1
person1.foo2.call(person2) // person1(箭头函数不绑定this)

person1.foo3()() // window
person1.foo3.call(person2)() // window
person1.foo3().call(person2) // person2

person1.foo4()() // person1
person1.foo4.call(person2)() // person2
person1.foo4().call(person2) // person1(箭头函数不绑定this)

// 上层作用域的理解
// var obj = {
//   name: "obj",
//   foo: function() {
//     // 上层作用域是全局
//   }
// }

// function Student() {
//   this.foo = function() {

//   }
// }

面试题4

var name = 'window'

function Person (name) {
  this.name = name
  this.obj = {
    name: 'obj',
    foo1: function () {
      return function () {
        console.log(this.name)
      }
    },
    foo2: function () {
      return () => {
        console.log(this.name)
      }
    }
  }
}

var person1 = new Person('person1')
var person2 = new Person('person2')

person1.obj.foo1()() // window
person1.obj.foo1.call(person2)() // window
person1.obj.foo1().call(person2) // person2

person1.obj.foo2()() // obj
person1.obj.foo2.call(person2)() // person2
person1.obj.foo2().call(person2) // obj