js基础篇(1)— this指向问题分析

173 阅读3分钟

什么是this?

  • 解析器在调用函数每次都会向函数内部传递一个隐含的参数,这个隐含的参数就是this,并且this指向一个对象,这个对象我们称之为函数执行的上下文对象。

this指向总结

  1. 当this不在函数内时,this指向永远为Window
  2. 以函数的形式调用时(function定义),this永远都指向Window
  3. 以方法的形式调用时(function定义),this指向调用该方法的那个对象
  4. 箭头函数不绑定this,this指向为定义时所在对象(或者可以理解为继承了外部的this)
  5. 构造函数中的this与被创建的新对象绑定
  6. call、apply、bind可以改变this的指向,使其指向传入对象

this指向分析

1. 当this不在函数内时

  • 当this不在函数内时,this永远指向Window
var name = "张三"
var a = {
    name: "李四",
    children: {
        name: this.name, // 张三
        obj: this        // Window
    }
}

console.log(a.children.name)
console.log(a.children.obj)

2. 以函数的形式调用时(function定义)

  • 以函数的形式调用,其实是call语法糖,传入参数是Window 即:
var name = "张三";
function sayHello(person) {
    console.log(`你好${this.name},我是${person}!`);
}
sayHello("李四"); // 你好张三,我是李四!
// 即为 sayHello.call(Window, "李四") 的语法糖
// sayHello("李四") === sayHello.call(Window, "李四")
  • 易混淆的地方:
var name = "张三"
var a = {
    name: "李四",
    hello: function () {
        console.log(this) // Window
        console.log(this.name) // "张三"
    }
}

var b = {
    name: "王五",
    hello: function(fun) {
        fun()
    }
}

b.hello(a.hello)
注意:

即使函数调用的位置是在另一个函数内,或以参数形式传入,this指向也是Window!!

3. 以方法的形式调用时(function定义)

  • 以方法形式调用时,也是call语法糖,但是传入参数是方法所在的对象
var name = "张三"
var a = {
    name: "李四",
    hello: function () {
        console.log(this.name)
    }
}
a.hello() // 李四
// a.hello() === a.hello.call(a)

4. 箭头函数中的this指向

  • 箭头函数中的this是在定义函数的时候绑定的,而不是在执行函数的时候绑定的
  • 箭头函数根本没有自己的this,导致箭头函数内部的this就是定义时所在的对象(或者可以理解为继承外层的this)
  • 正因为箭头函数没有this,所以不能用作构造函数
var name = "张三"
var a = {
    name: "李四",
    children: {
        name: "王五",
        obj: this, // Window
        hello1: () => console.log(this, this.name) // Window 张三
    }
}

a.children.hello1()
// 定义a对象时,a所在对象为Window
// 所以a内的箭头函数的this为Window

a.children.hello2 = () => cosole.log(this, this.name) // Window 张三
// 定义a.chidren.hello2时,a.chidren.hello2整体所在对象也为Window
// 或者也可以理解为 继承了 children对象 中的this,即Window
a.children.hello2()
  • 易混淆的地方:
var name = "张三";
var a = {
    name: "李四",
    hello: function() {
        return () => console.log(this, this.name)
        // { name: "李四", hello:f } 李四
    }
}
 
a.hello()();
注意:

a.hello为function定义,遵循第三条规则,所以a.hello中的this指向a,所以a.hello() 箭头函数中的this指向a

与function定义的函数的区别:
var name = "张三"
var a = {
    name: "李四",
    children: {
        name: "王五",
        hello: function () {
            return console.log(this, this.name)
        }
    }
}

a.children.hello() // { name: "王五", hello: f } 王五
// 这里遵循第三条规则,this指向children对象

5. 构造函数中的this指向

  • 构造函数中的this与被创建的新对象绑定
function Hello(name) {
    this.name = name
    console.log(this) // Hello { name: "张三" }
    console.log(this.name) // 张三
}

var a = new Hello("张三")
// 现在 Hello构造函数中的this指向即为 a

6. call、apply、bind对this指向的影响

  • call、apply、bind都可以改变this的指向,使其指向传入对象
b.call(a) // this由b指向a
b.apply(a) // this由b指向a
b.bind(a) // this由b指向a
// 三者具体用法及区别请查阅官方文档