this 是 JavaScript 中的一个关键字,它可以指向 window、函数、对象、全局变量,甚至是一个 Dom 元素,this 这是闹哪样啊?this 到底是指向什么?“模棱两可”的 this 几乎把前端开发们逼疯了。但我认为“模棱两可”的 this 恰恰是 JavaScript 灵活性的体现,如果摸清 this 的“脾气”,不旦不会加剧程序的复杂性,反而会让我们的代码更健壮。
this 的“脾气”并非是老虎的 P 股摸不得。我对使用 this 的场景作了一下分类,不过大家要知道,不管 this 的用法有多少,都是万变不离其宗的,它的宗旨可以总结成两句话,第一句话引自《JavaScript 权威指南》中很精辟的描述:JavaScript 中的函数运行在它们被定义的作用域里,而不是它们被执行的作用域里;第二句话引自 WanGe 同样很精辟的描述:this 指向的是调用该函数或者对象的拥有者。
带着这两句话,我们来看一下 this 可能存在的场景:
一、全局中的 this
这里说的全局,不是嵌套函数中相对的全局变量,而是相对于宿主环境,也就是我们浏览器的全局,来看一段代码或许你就明白了。
1 2 3 4 5 |
var name = 'WanGe'; console.log(name); console.log(this.name); console.log(window.name); console.log(self.name); |
可以看到,在全局环境下,以上四个 console.log() 的结果都是 ‘WanGe’,其中调用 name 的 this 是 window 对象,所以此时 this === window。
二、对象中的 this
1 2 3 4 5 6 7 |
var wange = { name: 'WanGe', say: function() { alert('My Name is ' + this.name); } }; wange.say(); |
还记得那句很精辟的描述吗?“this 指向的是调用该函数或者对象的拥有者。”配合以上代码,可以相辅相成地对 this 在对象中的应用有个更好的理解。this.name 是被 wange 这个对象调用的,所以 this 指向的就是 wange,所以此时 this.name === wange.name。
三、构造函数中的 this
有了上面的铺垫,对构造函数中的 this 应该就不难理解了。不要把 JavaScript 的构造函数理解地太复杂,JavaScript 的构造函数和其他语言不太一样,它本身就是个函数,不需要关键字声明,所以和上面的例子很相似:
1 2 3 4 5 |
var Person = function() { this.name = 'WanGe'; }; var wange = new Person(); alert('My Name is ' + wange.name); |
Person 是个构造函数,其中的 this 没有任何指向性,但是实例化这个构造函数之后就不同了,this.name 被 wange 这个实例对象调用,所以构造函数中的 this 指向的是其实例化的对象。
四、事件绑定中的 this
还有一种非常常见但是并不推荐的写法,就是当 Html 与 JavaScript 耦合时,会出现类似这样的代码:
1 |
<input type="button" value="WanGe" onclick="alert('My name is ' + this.value)" /> |
this 的灵活性就体现在这里,因为它不仅仅可以指代 window、函数、对象、全局变量,在这里它还可以指代 Dom 元素。不过,同样是对事件的监听,我们要注意 JavaScript 和 jQuery 的区别,jQuery 中的 this 是经过封装的,指代的是当前形如 [‘body’] 对象的伪数组,和 JavaScript 中 this 指代的 Dom 对象还是有区别的。
五、call / apply 调用的 this
call 和 apply 经常被用作写回调方法,通俗来说,call 和 apply 就是把别人的方法拿来当作像自己的方法一样用。不知道这样“通俗”的解释够不够通俗。还是先看一段代码吧:
1 2 3 4 5 6 7 |
var wange = { name: 'WanGe' }; var say = function() { alert('My name is ' + this.name); }; say.call(wange); |
和构造函数类似,这里的 say 方法中,this 也没有任何指向性,但是这里 say 通过 call 把对象 wange “借来” 当作是自己的对象来用,换句话说,this.name === wange.name。
this 的使用场景大致就是以上几种,关键还是要把握 this 所在的作用域。当我们真正能运用自如的时候,就会发现 this 这个关键字是 JavaScript 设计中的一个亮点。