• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号
您的位置:首页 > 程序设计 >JavaScript > JavaScript中的this陷阱的最全收集并整理(没有之一)

JavaScript中的this陷阱的最全收集并整理(没有之一)

作者:yuanzm 字体:[增加 减小] 来源:互联网 时间:2017-05-11

yuanzm通过本文主要向大家介绍了javascript:,javascript:void 0,javascript学习,开启javascript,javascript教程视频等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

当有人问起你JavaScript有什么特点的时候,你可能立马就想到了单线程、事件驱动、面向对象等一堆词语,但是如果真的让你解释一下这些概念,可能真解释不清楚。有句话这么说:如果你不能向一个6岁小孩解释清楚一个东西,那么你自己也不懂这个东西。这句话或许有点夸张,但是极其有道理。个人觉得,如果需要掌握一门语言,掌握它的API只是学了皮毛,理解这门语言的精髓才是重点。提及JavaScript的精髓,this、闭包、作用域链、函数是当之无愧的。这门语言正式因为这几个东西而变得魅力无穷。

  博客的标题是《JavaScript中的this陷阱的最全收集--没有之一》,很显然这篇博客阐述的是this。相信做过JavaScript开发的人都遇到过不少this的陷阱,我自己本身也遇到过不少坑,但是如果非要给出一个系统的总结的话,还没有足够的底蕴。非常幸运的是,今天早上起来看《Hacker News》的时候,恰巧看到了一篇有关于JavaScript this的解析:all this。于是,本着学习和共享的精神,决定将它翻译成中文。翻译的目的绝对不是为了当大自然的搬运工,在这个过程中会完全弄明白别人的著作,加深认识,同时将好东西分享给别人,才能让更多的学习者站在巨人的肩膀上前进。按照我自己的习惯,会翻译的过程中加上一些自己解释(引用部分),毕竟中西方人的思考方式是有差异的。当然文章标题所述的最全也不是吹的,文章非常长。

JavaScript来自一门健全的语言,所以你可能觉得JavaScript中的this和其他面向对象的语言如java的this一样,是指存储在实例属性中的值。事实并非如此,在JavaScript中,最好把this当成哈利波特中的博格特的背包,有着深不可测的魔力。

  下面的部分是我希望我的同事在使用JavaScript的this的时候应当知道的。内容很多,是我学习好几年总结出来的。

JavaScript中很多时候会用到this,下面详细介绍每一种情况。在这里我想首先介绍一下宿主环境这个概念。一门语言在运行的时候,需要一个环境,叫做宿主环境。对于JavaScript,宿主环境最常见的是web浏览器,浏览器提供了一个JavaScript运行的环境,这个环境里面,需要提供一些接口,好让JavaScript引擎能够和宿主环境对接。JavaScript引擎才是真正执行JavaScript代码的地方,常见的引擎有V8(目前最快JavaScript引擎、Google生产)、JavaScript core。JavaScript引擎主要做了下面几件事情:

  • 一套与宿主环境相联系的规则;
  • JavaScript引擎内核(基本语法规范、逻辑、命令和算法);
  • 一组内置对象和API;
  • 其他约定。

但是环境不是唯一的,也就是JavaScript不仅仅能够在浏览器里面跑,也能在其他提供了宿主环境的程序里面跑,最常见的就是nodejs。同样作为一个宿主环境,nodejs也有自己的JavaScript引擎--V8。根据官方的定义:
Node.js is a platform built on Chrome's JavaScript runtime for easily building fast, scalable network applications

global this

在浏览器里,在全局范围内,this等价于window对象。

<script type="text/javascript">
   console.log(this === window); //true
</script>
</div>

在浏览器里,在全局范围内,用var声明一个变量和给this或者window添加属性是等价的。

 <script type="text/javascript">
   var foo = "bar";
   console.log(this.foo); //logs "bar"
   console.log(window.foo); //logs "bar"
 </script>
</div>

如果你在声明一个变量的时候没有使用var或者let(ECMAScript 6),你就是在给全局的this添加或者改变属性值。

 <script type="text/javascript">
   foo = "bar";
 
   function testThis() {
    foo = "foo";
   }
 
   console.log(this.foo); //logs "bar"
   testThis();
   console.log(this.foo); //logs "foo"
 </script>
</div>

在node环境里,如果使用REPL(Read-Eval-Print Loop,简称REPL:读取-求值-输出,是一个简单的,交互式的编程环境)来执行程序,this并不是最高级的命名空间,最高级的是global.

> this
{ ArrayBuffer: [Function: ArrayBuffer],
 Int8Array: { [Function: Int8Array] BYTES_PER_ELEMENT: 1 },
 Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 },
 ...
> global === this
true
</div>

在node环境里,如果执行一个js脚本,在全局范围内,this以一个空对象开始作为最高级的命名空间,这个时候,它和global不是等价的。

 test.js脚本内容:

 console.log(this);
 console.log(this === global);
</div>

 REPL运行脚本:

 $ node test.js
 {}
 false
</div>

 在node环境里,在全局范围内,如果你用REPL执行一个脚本文件,用var声明一个变量并不会和在浏览器里面一样将这个变量添加给this。

 test.js:
 
 var foo = "bar";
 console.log(this.foo);
 
 $ node test.js
 undefined
</div>

但是如果你不是用REPL执行脚本文件,而是直接执行代码,结果和在浏览器里面是一样的(神坑)

 > var foo = "bar";
 > this.foo
 bar
 > global.foo
 bar
</div>

在node环境里,用REPL运行脚本文件的时候,如果在声明变量的时候没有使用var或者let,这个变量会自动添加到global对象,但是不会自动添加给this对象。如果是直接执行代码,则会同时添加给global和this

 test.js
 
 foo = "bar";
 console.log(this.foo);
 console.log(global.foo);
 
 $ node test.js
 undefined
 bar
</div>

上面的八种情况可能大家已经绕晕了,总结起来就是:在浏览器里面this是老大,它等价于window对象,如果你声明一些全局变量(不管在任何地方),这些变量都会作为this的属性。在node里面,有两种执行JavaScript代码的方式,一种是直接执行写好的JavaScript文件,另外一种是直接在里面执行一行行代码。对于直接运行一行行JavaScript代码的方式,global才是老大,this和它是等价的。在这种情况下,和浏览器比较相似,也就是声明一些全局变量会自动添加给老大global,顺带也会添加给this。但是在node里面直接脚本文件就不一样了,你声明的全局变量不会自动添加到this,但是会添加到global对象。所以相同点是,在全局范围内,全局变量终究是属于老大的。

function this
无论是在浏览器环境还是node环境, 除了在DOM事件处理程序里或者给出了thisArg(接下来会讲到)外,如果不是用new调用,在函数里面使用this都是指代全局范围的this。

 <script type="text/javascript">
   foo = "bar";
 
   function testThis() {
    this.foo = "foo";
   }
 
   console.log(this.foo); //logs "bar"
   testThis();
   console.log(this.foo); //logs "foo"
 </script>
</div>
test.js

foo = "bar";

function testThis () {
 this.foo = "foo";
}

console.log(global.foo);
testThis();
console.log(global.foo);
$ node test.js
bar
foo
</div>

除非你使用严格模式,这时候this就会变成undefined。

 <script type="text/javascript">
   foo = "bar";
 
   function testThis() {
    "use strict";
    this.foo = "foo";
   }
 
   console.log(this.foo); //logs "bar"
   testThis(); //Uncaught TypeError: Cannot set property 'foo' of undefined 
 </script>
</div>

如果你在调用函数的时候在前面使用了new,this就会变成一个新的值,和global的this脱离干系。

 <script type="text/javascript">
   foo = "bar";
 
   function testThis() {
    this.foo = "foo";
   }
 
   console.log(this.foo); //logs "bar"
   new testThis();
   console.log(this.foo); //logs "bar"
 
   console.log(new testThis().foo); //logs "foo"
 </script>
</div>

我更喜欢把新的值称作一个实例。

函数里面的this其实相对比较好理解,如果我们在一个函数里面使用this,需要注意的就是我们调用函数的方式,如果是正常的方式调用函数,this指代全局的this,如果我们加一个new,这个函数就变成了一个构造函数,我们就创建了一个实例,this指代这个实例,这个和其他面向对象的语言很像。另外,写JavaScript很常做的一件事就是绑定事件处理程序,也就是诸如button.addEventListener(‘click', fn, false)之类的,如果在fn里面需要使用this,this

分享到:QQ空间新浪微博腾讯微博微信百度贴吧QQ好友复制网址打印

您可能想查找下面的文章:

  • JavaScript仿微信打飞机游戏
  • JavaScript中双向数据绑定详解
  • javascript 中null和undefined区分和比较
  • javascript九宫格图片随机打乱位置的实现方法
  • JavaScript实现审核流程状态的动态显示进度条
  • JavaScript基本类型值-Undefined、Null、Boolean
  • javascript 使用正则test( )第一次是 true,第二次是false
  • 在javascript中,null>=0 为真,null==0却为假,null的值详解
  • JavaScript中的this陷阱的最全收集并整理(没有之一)
  • JavaScript中 this 指向问题深度解析

相关文章

  • 2017-05-11基于Vue2.0的分页组件
  • 2017-05-11Node.js的特点详解
  • 2017-05-11js原生Ajax的封装和原理详解
  • 2017-05-11原生js实现瀑布流布局
  • 2017-05-11jacascript DOM节点——元素节点、属性节点、文本节点
  • 2017-05-11jQuery实现 上升、下降、删除、添加一行代码
  • 2017-05-11js判断手机号是否正确并返回的实现代码
  • 2017-05-11angular实现form验证实例代码
  • 2017-05-11jquery hover 不停闪动问题的解决方法(亦为stop()的使用)
  • 2017-05-11Angular.JS利用ng-disabled属性和ng-model实现禁用button效果

文章分类

  • JavaScript
  • ASP.NET
  • PHP
  • 正则表达式
  • AJAX
  • JSP
  • ASP
  • Flex
  • XML
  • 编程技巧
  • Android
  • swift
  • C#教程
  • vb
  • vb.net
  • C语言
  • Java
  • Delphi
  • 易语言
  • vc/mfc
  • 嵌入式开发
  • 游戏开发
  • ios
  • 编程问答
  • 汇编语言
  • 微信小程序
  • 数据结构
  • OpenGL
  • 架构设计
  • qt
  • 微信公众号

最近更新的内容

    • 微信小程序 常用工具类详解及实例
    • 详解axios在node.js中的post使用
    • canvas实现十二星座星空图
    • 原生JS实现垂直手风琴效果
    • JS常用倒计时代码实例总结
    • 利用JavaScript在网页实现八数码启发式A*算法动画效果
    • jQuery中on方法使用注意事项详解
    • JavaScript中清空数组的三种方式
    • 超全面的javascript中变量命名规则
    • 微信小程序去哪里找 小程序到底如何使用(附小程序名单)

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有