JavaScript中的陷阱大集合(一)

Stella981
• 阅读 564

函数和操作符

1、双等号

==操作符比较时会进行类型的强制转换,这意味着它可以比较两个不同类型的对象,在执行比较之前它将会尝试把这两个对象转换成同一个类型,举一个例子:

"1" == 1 //true

然而,这样往往会误导我们,而且我们也不需要这样子来比较。在上面的例子中,我们完全可以先将字符串转换成数字型,然后利用对类型敏感的三重等号(===)来进行比较,如:

Number("1") === 1; //true

或者,更好的是,确保你放在首位的操作数的类型是正确的。由于双等号具有强制类型转换的行为,所以它会打破一般的传递性规则,这点有点吓人,请看下面的列子:

  1. "" == 0 //true - 空字符串会被强制转换为数字0.
  2. 0 == "0" //true - 数字0会被强制转换成字符串"0"
  3. "" == "0" //false - 两操作数都是字符串所以不执行强制转换

如果使用三重等号,上面的三个比较都将返回false。

2、parseInt不把10作为数字基数

如果你忽略parseInt的第二个参数,那么数字的基数将由下面的规则所决定:

◆    默认基数为10,即按10进制解析

◆    如果数字以0x开头,那么基数为16,即按16进制解析

◆    如果数字以0开头,那么基数为8,即按8进制解析

一个常见的错误是我们让用户输入以0开头的数字,这时候它就按8进制的方式去解析了,于是我们就看到了如下的效果:

  1. parseInt("8"); //8
  2. parseInt("08"); //0

因此,我们很多时候都会指定parseInt的第二个参数,如下所示:

  1. parseInt("8", 10); //8
  2. parseInt("08", 10); //8

ECMAScript5方面的说明:ECMAScript已不再支持8进制的解析假设,另外,如果忽略parseInt的第二个参数将会引起JSLint的警告。

3、字符串替换

字符串替换函数仅仅会替换第一个匹配项,并不能替换你所期望的全部匹配项。如下代码:

  1. "bob".replace("b", "x"); // "xob"
  2. "bob".replace(/b/, "x"); // "xob" (使用了正则表达式) 、

如果要替换所有的匹配项,我们可以使用正则表达式,并为他它添加全局修饰符,如下代码:

  1. "bob".replace(/b/g, "x"); // "xox"
  2. "bob".replace(new RegExp("b", "g"), "x"); // "xox" (alternate explicit RegExp)

全局修饰符确保了替换函数找到第一个匹配项后不会停止对下一个匹配项的替换。

4、“+"操作符会执行相加操作和字符串连接操作

php作为另一种弱类型语言,可以使用”.“操作符对字符串进行连接。Javascript却不是这样的 - 所以当操作数是字符串的时候”a+b“通常是执行连接操作。如果你想执行数字相加那你就要引起注意了,因为输入的内容可能是字符串类型的,所以你在执行相 加操作前需要先将其转换成数字类型,代码如下:

  1. 1 + document.getElementById("inputElem").value; // 连接操作
  2. 1 + Number(document.getElementById("inputElem").value); // 相加操作

需要注意的是,相减操作会尝试将操作数转换成数字类型,代码如下:

"3" - "1"; // 2

尽管有时候你想用减法将字符串从另一个字符串中减掉,但这时候往往会产生一些逻辑错误。

很多时候我们用数字和空串相加来实现数字转换成字符串的操作,代码如下:

3 + ""; // "3"

但是这样做并不好,所以我们可以用String(3)来取代上面的方法。

5、typeof

typeof这会返回一个javascript基本类型的实例的类型。Array实际上不是基本类型,所以typeof Array对象将返回Object,代码如下:

  1. typeof {} === "object" //true
  2. typeof "" === "string" //true
  3. typeof [] === "array"; //false

当你对自己的对象的实例使用这个操作符时将会得到相同的结果(typeof = "object")。

另外说明一点,”typeof null“将返回”object“,这个有点诡异。

6、instanceof

instanceof返回指定对象是否是由某个类构造的实例,这个对我们检查指定对象是否是自定义类型之一很有帮助,但是,如果你是用文本语法创建的内置类型那可能会得出错误的结果,代码如下:

  1. "hello" instanceof String; //false
  2. new String("hello") instanceof String; //true

由于Array实际上不是内置类型(只是伪装成内置类型 - 因此对它使用typeof不能得到预期的结果),但是使用instanceof就能得到预期效果了,代码如下所示:

  1. ["item1", "item2"] instanceof Array;  //true
  2. new Array("item1", "item2") instanceof Array;  //true

唉,不爽!总的来说,如果你想测试Boolean, String, Number, 或者Function的类型,你可以使用typeof,对于其他的任何类型,你可以使用instanceof测试。

哦,还有一点,在一个function中,有一个预定义变量叫“arguments”,它以一个array的形式传递给function。然而,它并不是真正的array,它只是一个类似array的对象,带有长度属性并且属性值从0-length。非常奇怪...你可以用下面的小伎俩将它转换成真正的数组:

var args = Array.prototype.slice.call(arguments, 0);

这个对由getElementsByTagName返回的NodeList对象也是一样的 - 它们都可以用以上的代码转换成合适的数组。

7、eval

eval 可以将字符串以javascript代码的形式来解析执行,但是一般来说我们不建议这么做。因为eval非常慢 - 当javascript被加载到浏览器中时,它会被编译成本地代码;然而执行的过程中每次遇到eval表达式,编译引擎都将重新启动执行编译,这样做的代 价太大了。而且这样做也丑陋无比,有很多eval被滥用的例子。另外,在eval中的代码会在当前范围内执行,因此它可以修改局部变量,以及在你的范围内 添加一些让你意想不到的东西。

JSON 转换是我们经常要做的;通常我们使用“var obj = eval(jsonText);”来进行转换。然而现在几乎所有的浏览器都支持本地JSON对象,你可以使用“var obj = JSON.parse(jsonText);”来替代前面的代码。相反你也可以用“JSON.stringify”将JSON对象转换成字符串。更妙的 是,你可以使用“jQuery.parseJSON”来完成上述的工作。

setTimeout和setInterval函数的第一个参数可以用字符串作为函数体来解析执行,当然,我们也不建议这样做,我们可以用实际的函数来替代。

最后,Function的构造函数和eval非常像,唯一不同的是,Function构造函数是在全局范围内执行的。

9、with

with表达式将为你提供访问对象属性的速记方式,但我们是否应该使用它,仍然存在矛盾的观点。Douglas Crockford不太喜欢它。John Resig在他的书中有找了很多with的巧妙用法,但是他也承认这将会影响性能并且会产生一点混乱。来看看我们分离出来的with代码块,他不能准确地告诉我们现在正在执行什么,代码如下所示:

  1. with (obj) {
  2. bob = "mmm";
  3. eric = 123;
  4. }

我是否刚刚修改了一个叫bob的局部变量?或者我是否设置了obj.bob?如果obj.bob已经被定义,那么它将会被重置为“mmm”。否则,如果有 另一个bob在这个范围中,那么他将会被改变。否则,全局变量bob会被设置。最后,下面的写法可以非常明确地表达你的意思:

  1. obj.bob = "mmm";
  2. obj.eric = 123;

ECMAScript5说明:ES5严格的来说已经不支持with表达式。

未完待续......

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Karen110 Karen110
3年前
一篇文章带你了解JavaScript日期
日期对象允许您使用日期(年、月、日、小时、分钟、秒和毫秒)。一、JavaScript的日期格式一个JavaScript日期可以写为一个字符串:ThuFeb02201909:59:51GMT0800(中国标准时间)或者是一个数字:1486000791164写数字的日期,指定的毫秒数自1970年1月1日00:00:00到现在。1\.显示日期使用
Wesley13 Wesley13
3年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这