分析JS中this引发的bug


Posted in Javascript onDecember 12, 2017

在 js 中,this 这个上下文总是变化莫测,很多时候出现bug 总是一头雾水,其实,只要分清楚不同的情况下如何执行就可以了,以下就是我们给大家整理的相关内容:

在JavaScript中有一个很特别、很常用又常常让初学者很困扰的东西 ─ “this”,在这堂课中会来谈谈这个”this”。

this通常会指向一个对象,同时this会在不同的情境下指向不同的对象。让我们来看几个不同的情境,帮助我们更了解”this”。

window object (global object)

这里我们在三种不同情境去打印”this”,分别是在函数的最外层(outer environment)直接去执行;使用fuction statement去执行;使用function expression去执行(如果还不清楚function statement和function expression的差别,可以参考注1)。

分析JS中this引发的bug

结果会发现,这三个”this”都会指向同样的对象,也就是global environment的window object (global object):

分析JS中this引发的bug

这也就是说,我们可以直接利用这个function和this在window object建立新的属性:

在这里我们利用this.NewVariable = "..."来在window object建立新的属性,函数的最后,我们则可以直接console.log(NewVariable),这里之所以可以不用打this.NewVariable或window.NewVariable是因为任何在global object (window)的属性,我们都可以直接去使用它,而不用使用”.”。

分析JS中this引发的bug

跑出来的结果会像这样子:

分析JS中this引发的bug

它会打印出我们的”Create a new property”,同时,在window这个大的object中,我们也会找到NewVariable这个属性:

分析JS中this引发的bug

method in object

我们知道,在对象里的值如果是原生值(primitive type;例如,字串、数值、逻辑值),我们会把这个新建立的东西称为「属性(property)」;如果对象里面的值是函数(function)的话,我们则会把这个新建立的东西称为「方法(method)」。

在这里,我们就要来建立method:

首先,我们利用object literal的方式创建一个对象c,里面包含属性name和方法log。log是一个匿名函数(anonymous function),函数内容很简单,就是打印this而已(关于匿名函数可参考注1)。最后则是使用c.log的方式来执行该方法。

分析JS中this引发的bug

让我们来看看,这时候的”this”会是什么呢?

答案是对象c!

当这个函数是对象里面的method时,这时候的this就会指向到包含这个method的对象

分析JS中this引发的bug

JavaScript中关于this的一个bug

让我们更进一步延伸来看这个范例:

假设我们在method log?面多这一行this.name = "Updated Object C name"

分析JS中this引发的bug

因为我们知道”this”现在指的是对象c,所以可以想像的,当我执行这个method的时候,它会去变更c.name的值。

分析JS中this引发的bug

这个部分是没有什么大问题的,不过让我们继续看下去……。

假设我在method log?面在做一些变更,我在这个method?面,另外建立一个函数叫做setname,一样是用this.name = newname的方式来修改这个object c中name属性的值。

接着执行setname这个函数,希望把object c中name的属性值改成”New name for object c”,最后再去打印”this”来看一下。

分析JS中this引发的bug

结果我们会发现,对象c中name属性的值并没有变成”New name for object c”,竟然还是一样!?怎么会这样呢?

分析JS中this引发的bug

仔细一看,我们回来看一下我们的window object,我们会发现,在window object中发现了一个新的属性”name”,而且值是”New name for object c”。

分析JS中this引发的bug

这是什么意思呢?意思是原来我们刚刚在函数setname里面的this,指向到的是global object (window object),而不再是刚刚的object C!

分析JS中this引发的bug

我们在setname这个function中,用console.log(this)来看一下:

分析JS中this引发的bug

在log这个method中,我们一共执行了三次的console.log(this)结果如下:

第一个和第三个”this”指向到的是对象c,而第二个在setname中的this,指向的则是window object (global object),而这也就是为什么setname这个function没办法帮我们修改对象c中name属性的名称,因为”this”根本没指向到对象c。

分析JS中this引发的bug

而许多人都认为,这是JavaScript的一个bug。

那么我们可以怎么做

那么碰到上述的这个例子时,我们可以怎么做来避免指向到不同的对象呢?

许多人的解法是这样的,因为我们知道对象都是用的引用的方式,所以我们可以这样做

STEP 1

我们在整个函数的最上面加上一行var self = this(有些人会用var that = this)。由于引用的特性,self和this会指向到同一个对象,而this指向对象c,所以self一样会指向对象c。

STEP 2

接着,把方法log内原本使用的”this”都改成”self”,这样做可以确保self指向到的是c对象而不用担心会像上面的例子一样指向到错误的对象。

分析JS中this引发的bug

结果也如同我们预期的,在第二次console.log(self)的时候,就再次替换了对象c中name属性的值。

分析JS中this引发的bug

总结

让我们来总结一下:

如果我们是在全局环境建立函数并打印this,这时候this会指向到全局对象,也就是window对象。

如果我们是在对象里面创建函数,也就是方法(method)的情况时,这时候的this一般就会指向到包含这个方法的对象(之所以说”一般”是因为除了上述bug的情况之外)。

碰到method中可能会有不知道this指向到什么的情况时,为了避免不必要的错误,我们可以在method中的最上面建立一个变量,去把它指定成this(var self = this)。

4.如果真的还是不知道那个情况下的this会指向到什么,就console.log出来看看吧!

示例代码

// function statement
function a(){
 console.log(this);
 this.NewVariable = "Create a new property";
}
a();
console.log(NewVariable);
var c = {
 name:"The C object",
 log: function(){
 var self = this;
 self.name = "Updated object C name";
 console.log(self);
 
 var setname = function(newname){
  self.name = newname;
  console.log(self);
 }
 setname("New name for object c");
 console.log(self)
 }
}
c.log();
Javascript 相关文章推荐
Firefox中autocomplete="off" 设置不起作用Bug的解决方法
Mar 25 Javascript
JavaScript中的this实例分析
Apr 28 Javascript
纯JS实现的批量图片预览加载功能
Aug 14 Javascript
javascript实现模拟时钟的方法
May 13 Javascript
js限制文本框的输入内容代码分享(3类)
Aug 20 Javascript
深入理解$.each和$(selector).each
May 15 Javascript
jQuery插件dataTables添加序号列的方法
Jul 06 Javascript
浅谈Node.js:理解stream
Dec 08 Javascript
jQuery阻止移动端遮罩层后页面滚动
Mar 15 Javascript
详解Node.js利用node-git-server快速搭建git服务器
Sep 27 Javascript
浅谈Webpack核心模块tapable解析
Sep 11 Javascript
解决echarts 一条柱状图显示两个值,类似进度条的问题
Jul 20 Javascript
微信小程序使用progress组件实现显示进度功能【附源码下载】
Dec 12 #Javascript
基于input动态模糊查询的实现方法
Dec 12 #Javascript
详解vue.js之props传递参数
Dec 12 #Javascript
react实现菜单权限控制的方法
Dec 11 #Javascript
Angular 作用域scope的具体使用
Dec 11 #Javascript
angularjs实现柱状图动态加载的示例
Dec 11 #Javascript
Vue响应式原理深入解析及注意事项
Dec 11 #Javascript
You might like
PHP实现邮件群发的源码
2013/06/18 PHP
php自定义apk安装包实例
2014/10/20 PHP
在PHP中输出JS语句以及乱码问题的解决方案
2019/02/13 PHP
php适配器模式简单应用示例
2019/10/23 PHP
javascript网页关闭时提醒效果脚本
2008/10/22 Javascript
JavaScript Cookie显示用户上次访问的时间和次数
2009/12/08 Javascript
jQuery 表单验证扩展(三)
2010/10/20 Javascript
js的一些常用方法小结
2011/06/29 Javascript
javascript实现点击按钮弹出一个可关闭层窗口同时网页背景变灰的方法
2015/05/13 Javascript
JS功能代码集锦
2016/05/04 Javascript
使用JS实现图片展示瀑布流效果(简单实例)
2016/09/06 Javascript
Javascript封装id、class与元素选择器方法示例
2017/03/13 Javascript
JS实现的全排列组合算法示例
2017/10/09 Javascript
express如何使用session与cookie的方法
2018/01/30 Javascript
在Vue项目中引入腾讯验证码服务的教程
2018/04/03 Javascript
详解使用React.memo()来优化函数组件的性能
2019/03/19 Javascript
JavaScript面试技巧之数组的一些不low操作
2019/03/22 Javascript
详解vue-element Tree树形控件填坑路
2019/03/26 Javascript
Async/Await替代Promise的6个理由
2019/06/15 Javascript
微信小程序引入模块中wxml、wxss、js的方法示例
2019/08/09 Javascript
如何正确理解vue中的key详解
2019/11/02 Javascript
Vuex实现数据共享的方法
2019/12/20 Javascript
vue中watch和computed为什么能监听到数据的改变以及不同之处
2019/12/27 Javascript
一看就会的vuex实现登录验证(附案例)
2020/01/09 Javascript
js实现简单的轮播图效果
2020/12/13 Javascript
[01:45:05]VGJ.T vs Newbee Supermajor 败者组 BO3 第二场 6.6
2018/06/07 DOTA
Python格式化压缩后的JS文件的方法
2015/03/05 Python
Python中的默认参数实例分析
2018/01/29 Python
django 实现将本地图片存入数据库,并能显示在web上的示例
2019/08/07 Python
关于建议书的格式范文
2014/05/20 职场文书
小学亲子活动总结
2014/07/01 职场文书
雨花台导游词
2015/02/06 职场文书
2015年法律事务部工作总结
2015/07/27 职场文书
python中取整数的几种方法
2021/11/07 Python
国际最新研究在陨石中发现DNA主要成分 或由陨石带来地球
2022/04/29 数码科技
Mysql表数据比较大情况下修改添加字段的方法实例
2022/06/28 MySQL