this指向

191 阅读2分钟

es5 this指向分四种情况

情况一:纯粹的函数调用
  • 这是函数的最通常用法,属于全局性调用,因此this就代表全局对象。
var x = 1;
function test() {
   console.log(this.x);
}
test();  // 1
情况二:作为对象方法的调用
  • 函数还可以作为某个对象的方法调用,这时this就指这个上级对象。
function test() {
  console.log(this.x);
}
var obj = {};
obj.x = 1;
obj.m = test;

// 类似这种写法
 var obj = {
    x:"1",
    m: function() {
        console.log(this.x);
    }
}
console.log(obj.m())

obj.m(); // 1
情况三 作为构造函数调用
  • 所谓构造函数,就是通过这个函数,可以生成一个新对象。这时,this就指这个新对象。
function test() {
  this.x = 1;
}

var obj = new test();
obj.x // 1
  • 运行结果为1。为了表明这时this不是全局对象,我们对代码做一些改变:
var x = 2;
function test() {
  this.x = 1;
}

var obj = new test();
obj.x  // 1

  • 运行结果为1,表明全局变量x的值根本没变。
情况四 apply,call,bind 调用
  • apply
var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.apply(a),100);
        }
    };

    a.func2()            // Cherry
  • call
var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(function () {
                this.func1()
            }.call(a),100);
        }
    };

    a.func2()            // Cherry
  • bind
 var a = {
        name : "Cherry",
        func1: function () {
            console.log(this.name)
        },
        func2: function () {
            setTimeout(  function () {
                this.func1()
            }.bind(a)(),100);
        }
    };

    a.func2()            // Cherry

箭头函数和普通函数区别

* 没有 this,不能改变 this 绑定
* 不能通过 new 调用,当然也没有原型(prototype)
* 没有 arguments 对象,不能有相同命名参数
* 箭头函数虽然没有 this ,但是还是可以在内部使用 this 的
* this 的绑定取决于定义函数时的上下文环境
* 一旦函数调用,任何改变 this 的方法都无效

练习题

let x = 11111
let a = {
    x: 1,
    init() {
        // 箭头函数的 this 取决于 init,所以可以打印出 1
        document.addEventListener('click', () => console.log(this.x))
    },
    allowInit: () => {
        // allowInit 直接是个箭头函数,所以这时的 this 变成了 window
        // 但是并不会打印出 11111,使用 let 时变量也会被提升至块级作用域的顶部,但是只提升声明,不提升初始化
        console.log(this.x)
    },
    otherInit() {
        // 普通函数的 this 取决于调用函数的位置,this 指向 document
        // 如果想打印出 x,可以使用 bind
        document.addEventListener('click', function() {
            console.log(this.x)
        })
    }
}
a.init() // -> 1
a.allowInit() // -> undefined
a.otherInit() // -> undefined