|
先举一个生活例子:这里的小明是主语,如果没有这个主语,那么后面的代词『他』将毫无意义。有了主语,代词才有了可以指代的事物。
类比到JavaScript的世界中,我们在调用一个对象的方法的时候,需要先指明这个对象,再指明要调用的方法。- var xiaoming = {
- name: 'Xiao Ming',
- run: function() {
- console.log(`${this.name} seems happy`);
- },
- };
- xiaoming.run();
复制代码 在上面的例子中,第8行中的指定了方法运行时的主语。因此,在中,我们才可以用来代替这个对象。可以看到起了代词的作用。
同样的,对于一个JavaScript类,在将它初始化之后,我们也可以用类似的方法来理解:类的实例在调用其方法的时候,将作为主语,其方法中的就自然变成了指代主语的代词。- class People {
- constructor(name) {
- // 在用new关键字实例化一个对象的时候,相当于在说,
- // “创建一个People类实例(主语),它(this)的name是……”
- // 所以这里的this就是新创建的People类实例
- this.name = name;
- }
-
- run() {
- console.log(`${this.name} seems happy.`)
- }
- }
- // new关键字实例化一个类
- var xiaoming = new People('xiaoming');
- xiaoming.run();
复制代码 这就是我认为this关键字设计得精彩的地方!如果将调用方法的语句- var xiaoming = new People('xiaoming');
复制代码 和方法本身的代码连起来,像英语一样读,其实是完全通顺的。
this的绑定
句子的主语是可以变的,例如在下面的场景中,被赋值到小芳()身上之后,调用,主语就变成了小芳!- var xiaofang = {
- name: 'Xiao Fang',
- };
- var xiaoming = {
- name: 'Xiao Ming',
- run: function() {
- console.log(`${this.name} seems happy`);
- },
- };
- xiaofang.run = xiaoming.run;
- // 主语变成了小芳
- xiaofang.run();
复制代码 但是如果小明很抠门,不愿意将方法借给小芳以后,就变成了小芳的话,那么小明要怎么做呢?他可以通过Function.prototype.bind让运行时候的永远为小明自己。- var xiaofang = {
- name: 'Xiao Fang',
- };
- var xiaoming = {
- name: 'Xiao Ming',
- run: function() {
- console.log(`${this.name} seems happy`);
- },
- };
- // 将小明的run方法绑定(bind)后,返回的还是一个
- // 函数,但是这个函数之后被调用的时候就算主语不是小明,
- // 它的this依然是小明
- xiaoming.run = xiaoming.run.bind(xiaoming);
- xiaofang.run = xiaoming.run;
- // 主语虽然是小芳,但是最后this还是小明
- xiaofang.run();
复制代码 那么同一个函数被多次之后,到底是哪一次的对象呢?你可以自己尝试看看。
call与apply
允许你在调用一个函数的时候指定它的的值。- var xiaoming = {
- name: 'Xiao Ming'
- };
- function run(today, mood) {
- console.log(`Today is ${today}, ${this.name} seems ${mood}`);
- }
- // 函数的call方法第一个参数是this的值
- // 后续只需按函数参数的顺序传参即可
- run.call(xiaoming, 'Monday', 'happy')
复制代码 和的功能是一模一样的,区别进在于,里将函数调用所需的所有参数放到一个数组当中。- var xiaoming = {
- name: 'Xiao Ming'
- };
- function run(today, mood) {
- console.log(`Today is ${today}, ${this.name} seems ${mood}`);
- }
- // apply只接受两个参数
- // 第二个参数是一个数组,这个数组的元素被按顺序
- // 作为run调用的参数
- run.apply(xiaoming, ['Monday', 'happy'])
复制代码 那么/和上面的混用的时候是什么样的行为呢?这个也留给大家自行验证。但是在一般情况下,我们应该避免混用它们,否则会造成代码检查或者调试的时候难以跟踪的值的问题。
当方法失去主语的时候,this不再有?
其实大家可以发现我的用词,当一个被调用的时候是有主语的时候,它是一个方法;当一个被调用的时候是没有主语的时候,它是一个函数。当一个函数运行的时候,它虽然没有主语,但是它的的值会是全局对象。在浏览器里,那就是。当然了,前提是函数没有被过,也不是被或所调用。
那么作为函数的情景有哪些呢?
首先,全局函数的调用就是最简单的一种。- function bar() {
- console.log(this === window); // 输出:true
- }
- bar();
复制代码 立即调用的函数表达式(IIFE,Immediately-Invoked Function Expression)也是没有主语的,所以它被调用的时候也是全局对象。- (function() {
- console.log(this === window); // 输出:true
- })();
复制代码 但是,当函数被执行在严格模式(strict-mode)下的时候,函数的调用时的this就是了。这是很值得注意的一点。- function bar() {
- 'use strict';
- console.log('Case 2 ' + String(this === undefined)); // 输出:undefined
- }
- bar();
复制代码 不可见的调用
有时候,你没有办法看到你定义的函数是怎么被调用的。因此,你就没有办法知道它的主语。下面是一个用jQuery添加事件监听器的例子。- window.val = 'window val';
- var obj = {
- val: 'obj val',
- foo: function() {
- $('#text').bind('click', function() {
- console.log(this.val);
- });
- }
- };
- obj.foo();
复制代码 在事件的回调函数(第6行开始定义的匿名函数)里面,的值既不是,又不是,而是页面上为的HTML元素。- var obj = {
- foo: function() {
- $('#text').bind('click', function() {
- console.log(this === document.getElementById('text')); // 输出:true
- });
- }
- };
- obj.foo();
复制代码 这是因为匿名函数是被jQuery内部调用的,我们不知道它调用的时候的主语是什么,或者是否被等函数修改过的值。所以,当你将匿名函数交给程序的其他部分调用的时候,需要格外地谨慎。
如果我们想要在上面的回调函数里面使用obj的值,除了直接写之外,还可以在foo方法中用一个新的变量来保存运行时的值。这样说有些绕口,我们看下例子便知。- window.val = 'window val';
- var obj = {
- val: 'obj val',
- foo: function() {
- var that = this; // 保存this的引用到that,这里的this实际上就是obj
- $('#text').bind('click', function() {
- console.log(that.val); // 输出:obj val
- });
- }
- };
- obj.foo();
复制代码 另外一种方法就是为该匿名函数了。- window.val = 'window val';
- var obj = {
- val: 'obj val',
- foo: function() {
- $('#text').bind('click', function() {
- console.log(this.val); // 输出:obj val
- }.bind(this));
- }
- };
- obj.foo();
复制代码 总结
在JavaScript中的用法的确是千奇百怪,但是如果利用自然语言的方式来理解,一切就顺理成章了。不知道你读完这篇文章的时候理解了吗?
以上就是JavaScript中的this关键字用法详解的详细内容,更多关于JavaScript this关键字的资料请关注脚本之家其它相关文章!
来源:https://www.jb51.net/article/284012.htm
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作! |
|