js 的 this 是个比较令人头疼的东西,尤其是在面试的时候,深受面试官的喜爱。我们今天来谈谈 js 中的 this
this 是什么,为什么要用 this 它是一个在每个函数作用域中自动定义的特殊标识符关键字, this机制提供了更优雅的方式来隐含地“传递”一个对象引用,导致更加干净的 API 设计和更容易的复用。当我们的代码和使用环境约复杂,我们就越能感受到 this 的重要性
先看一段代码
let x = { num: 1, sum: function(data) { return this.num + data } } let y = { num: 1, sum: function(data) { return this.num + data } } let y_sum = y.sum console.log(x.sum(1)) // 2 console.log(y_sum(1)) // NaN单从上面的代码来看,两者似乎没有区别,但是运行后的结果确是不一样的
在看一段代码
let x = { num: 1, sum: function(data) { return this.num + data } } let y = { num: 1, sum: data => { return this.num + data } } console.log(x.sum(1)) // 2 console.log(y.sum(1)) // NaN也是一样,看着俩段代码差别不大,但是结果却完全不一样
var num = 2 var obj = { num: 1, say: function () { setTimeout(function(){ console.log(this.num) // 2 }, 0) } } obj.say()一般函数的this指向是指执行该函数的运行对象
let x = { num: 1, sum: function(data) { return this.num + data // 这里的this是指运行了sum函数的x。所以this.num = 1 } } let y = { num: 1, sum: function(data) { return this.num + data // 由于这里运行sum函数的不再是y而是window。所以这里相当于window.num = undefined } } let y_sum = y.sum console.log(x.sum(1)) // 2 console.log(y_sum(1)) // NaN箭头函数的指向是指向运行该函数的父执行上下文的this,箭头函数中的this是在定义函数的时候绑定,而不是在执行函数的时候绑定。
let x = {
num: 1, sum: function(data) { return this.num + data // 这里的this指的是x } } let y = { num: 1, sum: data => { return this.num + data } // 这里因为是箭头函数,所以这里的this在sum函数定义的时候就开始绑定了,这里的this是window } console.log(x.sum(1)) // 2 console.log(y.sum(1)) // NaN var obj = { say: function () { let _say = () => { console.log(this); // 这里的this就是say,因为在定义_say时,_say会去拿父执行上下文的this } return _say() } } obj.say()对于匿名函数来说,this的指向是window
var num = 2 var obj = { num: 1, say: function () { setTimeout(function(){ console.log(this.num) // 2 // 这里的this是window }, 0) } } obj.say() // 这里如果是箭头函数,结果又不一样了 var obj2 = { num: 1, say: function () { setTimeout(() =>{ console.log(this.num) // 1 }, 0) } } obj2.say()虽然有的时候,函数会在window下调用,this会指向window对象,但是this 不会以任何方式指向函数的 词法作用域
function foo() { var a = 2; this.bar(); } function bar() { console.log( this.a ); } foo(); //undefined开发者试图用 this 在 foo() 和 bar() 的词法作用域间建立一座桥,使得bar() 可以访问 foo()内部作用域的变量 a。这样的桥是不可能的。 你不能使用 this 引用在词法作用域中查找东西。这是不可能的。
更多练习
function foo() { console.log( this.a ); } var obj2 = { a: 42, foo: foo }; var obj1 = { a: 2, obj2: obj2 }; obj1.obj2.foo(); // 42 // 这里最终调用foo函数的依然是obj2 function foo() { console.log( this.a ); } function doFoo(fn) { // `fn` 只不过 `foo` 的另一个引用 // 在这里fn() != obj.foo() fn(); } var obj = { a: 2, foo: foo }; var a = "oops, global"; doFoo( obj.foo ); // "oops, global" var obj = { say: function () { function _say() { // this 是什么?想想为什么? console.log(this) } return _say.bind(obj) }() } obj.say() // 这里_say通过bind将this指向了obj,但是打印的结果却还是window,为什么呢? // 这里可以看作: 因为 = 赋值语句是由右向左运行的。所以这里的obj应该是个undefined,所以this指向了window换种写法就会完全不一样了
var obj = {} obj.say: function () { function _say() { console.log(this) } return _say.bind(obj) }() obj.say() // 这里this指向了obj