0%

this指向

this的绑定

一. 整理this的绑定规则

  • 默认绑定:独立函数调用,函数没有被绑定到某个对象上进行调用

  • 隐式绑定:通过某个对象发起的函数调用,在调用对象内部有一个对函数的引用。

  • 显式绑定:明确this指向的对象,第一个参数相同并要求传入一个对象。

    • apply/call
    • bind
  • new绑定:

    • 创建一个全新对象
    • 新对象被执行prototype链接
    • 新对象绑定到函数调用的this
    • 如果函数没有返回其他对象,表达式会返回这个对象

默认绑定

默认绑定this一般情况下是window

在严格模式下this为undefined

es6后的class中函数默认为严格模式,即this为undefined

1
2
3
4
5
6
7
8
9
10
11
class Test{
constructor(){

}
foo(){
console.log(this)
}
}
const test = new Test()
const bar = test.foo
bar() // undefined

babel会将js设置为严格模式——在React框架下,隐式绑定都为undefined

1
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
1
2
3
4
function foo(){
console.log(this)
}
foo() // undefined

二. 说出apply、call、bind函数的用法和区别

​ 用法:

  • ​ apply

    ​ 第一个参数: 绑定this

    ​ 第二个参数: 传入额外的实参, 以数组的形式

  • ​ call

    ​ 第一个参数: 绑定this

    ​ 参数列表: 后续的参数以多参数的形式传递, 会作为实参

  • ​ bind(不希望obj对象身上有函数)

    1
    2
        var bar = foo.bind(obj)
    bar() // this -> obj

    区别:

  • call、apply和bind都可以改变函数的this指向

  • call、apply和bind第一个参数的是this要指向的对象

  • call、apply和bind都可以后续为函数传参,apply是将参数并成一个数组,call和bind是将参数依次列出

  • call、apply都是直接调用,bind生成的this指向改变函数需要手动调用。

​ 绑定优先级:

​ 默认绑定的优先级最低、显示绑定的优先级高于隐式绑定、new绑定的优先级高于隐式绑定、new绑定优先级高于bind

​ new绑定和call、apply不可以一起使用

​ 注:

​ 显示绑定传入null或undefined,显示绑定会忽略使用默认规则

1
2
3
4
foo.call(null)
foo.call(undefined)
var bar = foo.bind(null)
bar() // 都是windows

三. 说出箭头函数的各种用法和简写

  • 基本写法

    • ():函数的参数

    • {}:函数的执行体

      1
      2
      3
      4
      var foo3 = (name, age) => {
      console.log("箭头函数的函数体")
      console.log(name, age)
      }
  • 优化写法

    • 只有一个参数时, 可以省略()

      1
      2
      3
      names.forEach(item => {
      console.log(item)
      })
  • 只有一行代码时, 可以省略{}

    1
    names.forEach(item => console.log(item))
  • 只要一行代码时, 表达式的返回值会作为箭头函数默认返回值, 所以可以省略return

    1
    2
    var newNums = nums.filter(item => item % 2 === 0)
    var newNums = nums.filter(item => item % 2 === 0)
  • 如果箭头函数默认返回的是对象, 在省略{}的时候, 对象必须使用()包裹 () => ({name: “why”})

    1
    2
    3
    4
    var arrFn = () => ["abc", "cba"]
    var arrFn = () => {} // 注意: 这里是{}执行体
    var arrFn = () => ({ name: "why" })
    console.log(arrFn())

四. 完成this的面试题解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var name = "window";
var person = {
name: "person",
sayName: function () {
console.log(this.name);
}
};
function sayName() {
var sss = person.sayName;
sss(); // window
person.sayName(); // person
(person.sayName)(); // person
(b = person.sayName)(); // window
}
sayName();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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 () {
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
// person1.foo4.call(person2)(); // person2
// person1.foo4().call(person2); // person1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
var name = 'window'
function Person (name) {
this.name = name
this.foo1 = function () {
console.log(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

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

// 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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