分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 软件开发

JS探秘——那些你理解存在偏差的问题

发布时间:2023-09-06 01:23责任编辑:彭小芳关键词:暂无标签

???????Javascript的连续赋值运算

???
???????
var a = {n:1}; ?a.x = a = {n:2}; ?alert(a.x); // --> undefined 
???
???

???????看 jQuery 源码 时发现的这种写法。 以上第二句 a.x = a = {n:2} 是一个连续赋值表达式。 这个连续赋值表达式在引擎内部究竟发生了什么?是如何解释的?

???

???????加一个变量 b,指向 a。

???
???????
var a = {n:1}; ?var b = a; // 持有a,以回查 ?a.x = a = {n:2}; ?alert(a.x);// --> undefined ?alert(b.x);// --> [object Object] 
???
???

???????实际执行过程:从右到左,a 先被赋值为 {n:2},随后 a.x 被赋值 {n:2}。第一步 a = {n:2} 的 a 指向的是新的对象 {n:2}, 第二步 ???????a.x = {n:2} 中的 a 是 {a:1}。如下所示

???
???????
 ????????????a.x ?= ?a ?= {n:2} ?????????????│ ?????│ ?????{n:1}<──┘ ?????└─>{n:2}
???
???

???????为什么 ++[[]][+[]]+[+[]] = 10?

???

???????++[[]][+[]]+[+[]],它相等于:

???
???????
++[[]][+[]]+[+[]]
???
???

???????在 JavaScript 里,+ 会把一些字符转化成数字,如 +"" === 0、+[] === 0,因此,我们可以简化一下(++ 比 + 有更高的优先级):

???
???????
++[[]][0]+[0]
???
???

???????因为 [[]][0] 的意思是:获取 [[]] 的第一个元素,这就得出了下面的结果:

???
    ???????
  • [[]][0] 返回内部数组 ([])。根据语言规范,我们说 [[]][0] === [] 是不正确的,但让我们把这个内部数组称作 A,以避免错误的写法。
  • ???????
  • ++[[]][0] == A + 1, 因为 ++ 的意思是”加一”。
  • ???????
  • ++[[]][0] === +(A + 1);换句话说,你得到的永远是个数值( +1 并不一定得到的是个数值,但 ++ 一定是)。
  • ???
???

???????我们可以把这一堆代码简化的更清晰。让我们把 A 换回成 [] :

???
???????
+([] + 1)+[0]
???
???

???????在 JavaScript 里,这也是正确的:[] + 1 === "1",因为 [] == "" (这相当于一个空的数组的内部元素连接),于是:

???
???????
+([] + 1) === +("” + 1),并且 +("” + 1) === +("1"),并且 +("1") === 1 
???
???

???????让我们再次简化一下:

???
???????
1+[0]
???
???

???????同样,在 Javascript 里,这是正确的:[0] == "0",因为这是相当于一个有一个元素的数组的内部元素的连接。 各元素会使用,分隔。 当只有一个元素时,你可以推论出这个过程的结果就是它自身的第一个元素。

???

???????所以,最终我们得到 (数字 + 字符串 = 字符串):

???
???????
1+"0"=== "10" // 耶!
???
???

???????[1,2] + [3,4]=="1,23,4"

???

???????JavaScript 的 + 运算符有两个目的:

???
    ???????
  1. 将两个数相加
  2. ???????
  3. 将两个字符串连接
  4. ???
???

???????规范并没有定义 + 运算符在数组上的行为,所以javascript 首先 把数组转换成字符串,然后在字符串上进行 + 运算。

???

???????如果想连接两个数组,可以使用数组的 concat 方法:

???
???????
[1, 2].concat([3, 4]) // [1, 2, 3, 4]
???
???

???????{}+{}等于多少?

???

???????结果为:NaN

???

???????这个问题的原因是,JavaScript 把第一个 {} 解释成了一个空的代码块(code block)并忽略了它。 NaN 其实是表达式 +{} 计算的结果 (+ ???????加号以及第二个 {})。 你在这里看到的 + 加号并不是二元运算符「加法」,而是一个一元运算符,作用是将它后面的操作数转换成数字,和 Number() 函数完全一样。例如: ???

???
???????
> +"3.65"3.65
???
???

???????以下的表达式是它的等价形式: ???

???
???????
+{}Number({})Number({}.toString()) ?// {}.valueOf() isn’t primitiveNumber("[object Object]")NaN
???
???

???????为什么第一个 {} 会被解析成代码块(code block)呢? 因为整个输入被解析成了一个语句:如果左大括号出现在一条语句的开头,则这个左大括号会被解析成一个代码块的开始。 ???????所以,你也可以通过强制把输入解析成一个表达式来修复这样的计算结果: (译注:我们期待它是个表达式,结果却被解析成了语句) ???

???
???????
> ({} + {})‘[object Object][object Object]‘
???
???

???????{} === {},结果为false

???

???????每个对象都有自己唯一的标识符,因此通过字面量或构造函数创建的对象和任何其他对象都不相等,我们可以通过 === 进行比较。 ???

???
???????
{} === {} //false
???
???

???????对象是通过引用来比较的,只有两个对象有相同的标识,才认为这个对象是相等的。 ???

???
???????
var obj = {}; obj === obj //true
???
???

???????原始值没有内部标识,原始值是按值比较的: 比较两个原始值的依据是他们的内容,如果两个原始值的内容相同,这认为这两个原始值相同。 ???

???
???????
"abc" === "abc" //true
???
???

???????原始值和它们的包装类型

???

???????原始值类型 boolean, number 以及 string 都有自己对应的包装类型 Boolean, Number 和 String。 包装类型的实例都是对象值,两种类型之间的转换也很简单: ???

???
    ???????
  • 转换为包装类型:new String("abc")
  • ???????
  • 转换为原始类型:new String("abc").valueOf()
  • ???
???

???????原始值类型以及它们相应的包装器类型有很多不同点,例如:

???
???????
 typeof "abc" //‘string‘ typeof new String("abc") //‘object‘ "abc" instanceof String //false new String("abc") instanceof String //true "abc" === new String("abc") //false
???
???

???????包装类型的实例是一个对象,因此和 JavaScript 和对象一样,包装类型也无法进行值的比较(只能比较引用)。

???
???????
 var a = new String("abc"); var b = new String("abc"); a == b //false(虽然 a 和 b 有相同的内容,但是依然返回 false) a == a //true
???
???

???????5.toFixed(3),报错SyntaxError: Unexpected token ILLEGAL

???

???????原始值没有自己的方法

???

???????包装对象类型很少被直接使用,但它们的原型对象定义了许多其对应的原始值也可以调用的方法。 例如,String.prototype 是包装类型 String 的原型对象。 ???????它的所有方法都可以使用在字符串原始值上。 包装类型的方法 String.prototype.indexOf 在字符串原始值上也有,它们并不是两个拥有相同名称的方法,而的的确确就是同一个方法:

???
???????
 "abc".charAt === String.prototype.charAttrue
???
???

???????在数字的包装类型 Number 的原型对象有 toFixed 方法,即 Number.prototype.toFixed,但是当我们写如下代码时却发生错误:

???
???????
 5.toFixed(3)SyntaxError: Unexpected token ILLEGAL
???
???

???????此错误是解析错误(SyntaxError),5 后面跟着一个点号(.),这个点被当作了小数点,而小数点后面应该是一个数,以下代码可以正常运行:

???
???????
 (5).toFixed(3)"5.000" 5..toFixed(3)"5.000"
???

JS探秘——那些你理解存在偏差的问题

原文地址:http://www.cnblogs.com/MasterYao/p/7810738.html

知识推荐

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved