分析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 相关文章推荐
基于jquery的滑动样例代码
Nov 20 Javascript
网页打开自动最大化的js代码
Aug 22 Javascript
JavaScript子窗口ModalDialog中操作父窗口对像
Dec 11 Javascript
CheckBoxList多选样式jquery、C#获取选择项
Sep 06 Javascript
jQuery extend 的简单实例
Sep 18 Javascript
JS中引用百度地图并将百度地图的logo和信息去掉
Sep 29 Javascript
Egret引擎开发指南之创建项目
Sep 03 Javascript
jquery基本选择器匹配多个元素的实现方法
Sep 05 Javascript
jQuery插件echarts实现的多折线图效果示例【附demo源码下载】
Mar 04 Javascript
Vue实现搜索 和新闻列表功能简单范例
Mar 16 Javascript
浅谈vuepress 踩坑记
Apr 18 Javascript
vue打包npm run build时候界面报错的解决
Aug 13 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下利用shell后台运行PHP脚本,并获取该脚本的Process ID的代码
2011/09/19 PHP
PHP错误和异长常处理总结
2014/03/06 PHP
thinkphp的URL路由规则与配置实例
2014/11/26 PHP
Mac OS下配置PHP+MySql环境
2015/02/25 PHP
php简单实现查询数据库返回json数据
2015/04/16 PHP
PHP实现针对日期,月数,天数,周数,小时,分,秒等的加减运算示例【基于strtotime】
2017/04/19 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
php生成HTML文件的类方法
2019/10/11 PHP
jQuery 剧场版 你必须知道的javascript
2009/05/27 Javascript
关于html+ashx开发中几个问题的解决方法
2011/07/18 Javascript
自己实现string的substring方法 人民币小写转大写,数字反转,正则优化
2012/09/02 Javascript
Function.prototype.call.apply结合用法分析示例
2013/07/03 Javascript
JS格式化数字金额用逗号隔开保留两位小数
2013/10/18 Javascript
讲解JavaScript中for...in语句的使用方法
2015/06/03 Javascript
js实现C#的StringBuilder效果完整实例
2015/12/22 Javascript
JS弹出窗口插件zDialog简单用法示例
2016/06/12 Javascript
Javascript字符串常用方法详解
2016/07/21 Javascript
提高JavaScript执行效率的23个实用技巧
2017/03/01 Javascript
React Native 搭建开发环境的方法步骤
2017/10/30 Javascript
微信小程序在其他页面监听globalData中值的变化
2019/07/15 Javascript
vue项目打包后请求地址错误/打包后跨域操作
2020/11/04 Javascript
Taro小程序自定义顶部导航栏功能的实现
2020/12/17 Javascript
[49:42]DOTA2上海特级锦标赛主赛事日 - 3 胜者组第二轮#2Secret VS EG第一局
2016/03/04 DOTA
Django中URLconf和include()的协同工作方法
2015/07/20 Python
解决Python安装后pip不能用的问题
2018/06/12 Python
python实现在遍历列表时,直接对dict元素增加字段的方法
2019/01/15 Python
Django如何简单快速实现PUT、DELETE方法
2019/07/24 Python
Python 中pandas索引切片读取数据缺失数据处理问题
2019/10/09 Python
股权转让意向书
2014/04/01 职场文书
一年级学生期末评语
2014/04/21 职场文书
2014年保卫科工作总结
2014/12/05 职场文书
2015年幼儿园大班工作总结
2015/04/25 职场文书
教师创先争优承诺书
2015/04/27 职场文书
家长对学校的意见和建议
2015/06/03 职场文书
小学主题班会教案
2015/08/17 职场文书
Java中的继承、多态以及封装
2022/04/11 Java/Android