Designed by 77
加载资源 ......
感谢 ♥ 作者
先不感谢了

javascript中的this理解

JavaScript中的this其实是一个很好理解的概念,只不过JavaScript对初学者隐藏了一些细节,促使初学者在理解this的时候对概念会特别模糊,这里来解释一下JavaScript中的this到底是什么东西。

函数调用中的this

不知道你有没有发现,在把对象和函数联系起来用的时候,会出现下面这种情况:

let obj = {
   name: 'yanggb',
   age: 18,
   hello: function(){
      console.log(`你好,我叫${this.name},我今年${this.age}岁了`)
   }
}
let sayHi = obj.hello
sayHi() // 你好,我叫,我今年undefined岁了
obj.hello() // 你好,我叫yanggb,我今年18岁了

sayHi函数和obj.hello函数都是相同的打印逻辑(sayHi也是obj.hello赋值给它的),但是打印的结果却不一样,这就是this的妙用了,因为两者的this不是同一个this,所以才会打印出不同的结果。

要知道它们的this指向,可以在函数调用的时候用call或者apply。

// 沿用上面的代码
sayHi.call(undefined) // 你好,我叫,我今年undefined岁了
obj.hello.call(obj) // 你好,我叫yanggb,我今年18岁了

可以看到,加上call后并不影响结果。事实上,在函数调用的后面加call才是最完全的写法,不加call的函数调用其实是JavaScript的一个语法糖。call的第一个参数就是这个函数所指向的this,在这里有个公式:

对象.函数名.call(对象, arguments)

谁引用了函数,谁就代表this,但如果像sayHi没有对象引用就直接调用的,它默认的this为null或undefined,那么浏览器就会自动把它的this变成window对象(window对象是浏览器内置的全局对象,因为函数是在全局上下文中执行的,this也就被替换成了window全局对象,而window全局对象的name属性是空字符串,window全局对象没有age属性,也就产生了相应的打印结果)。

[]语法中的this

var length = 10 // 用var把length属性挂载到window全局对象上作为全局属性
function fn() {
   console.log(this.length)
}
let obj = {
   length: 5,
   long: function(fn) {
      fn()
      arguments[0]()
   }
}
obj.long(fn, 1)

先别想这段代码是什么逻辑,我们先把所有的函数调用都加上call。

// 沿用上面代码
fn.call(undefined) // 打印出10
obj.long.call(obj,fn,1)

在fn和obj.long的调用加上call让结果一目了然,然后我们再给argument[0]调用加上call,直接套公式虽然不符合规范,但可以让我们更好地理解。

arguments[0].call(arguments) // 打印出 2

因为在这里的arguments[0]就是fn,this被替换为arguments对象(使用[]语法的对象会作为函数调用方),而arguments的长度是2,所以this.length的结果为2,是不是没想到还能这么用?this实在是太灵活了,其取值决定于函数被谁引用!

箭头函数

新出的ES6语法里的箭头函数没有this,所以在你需要用到this的时候最好使用ES5的函数语法。

而正是因为箭头函数里没有this,所以它才会继承上一层函数的this。这一点要格外注意,它与上一层函数之间并不存在谁指向谁。

总结

当你调用一个函数的时候,最好是call一下这个函数,它的第一个参数就代表this,这样有助于你理解代码。具体就是当你遇到一个函数而不清楚它的this到底指向谁的时候,你可以套用公式【对象.函数名.call(对象,arguments)】来帮助理解。

除了call以外还有apply,和call的功能以及使用方法基本一致,区别只在于call方法接受的是参数列表,而apply方法接受的是一个参数数组。

 

"因为我知道的比你多,我比你更懂事,所以日子让我比你更难过。"

posted @ 2020-07-01 23:18  yanggb  阅读(442)  评论(0编辑  收藏  举报