我的编程空间,编程开发者的网络收藏夹
学习永远不晚

JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析

本篇内容主要讲解“JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析”吧!

解释:为什么 ++[[]][+[]]+[+[]] = 10

[0]是一个带有0成员的数组,[0][0]是取它的第1个成员,所以必是0。

用了[0][0] = '1'虽然改了第1成员的值,但下一个[0][0]是独立的取成员值的表达式,所以得到0数字值。

[] = 1是右值不是iterable(可迭代的)造成的错误,这应该是”解构赋值”造成的错误,以不同的浏览器调试:

// Chrome TypeError: undefined is not a function   // Firefox TypeError: 1 is not iterable   // Safari TypeError: [] is not a function. (In '[]', '[]' is undefined)

数组解构赋值的话,右值必需是iterable(可迭代的),下面的例子的错误与[] =  1是一样错误,所以应该会先检查右值是否为iterable时,先抛出类型错误:

[] = {}; [] = undefined; [] = null;

***的,[] = '1'不会有错误,是因为字符串是属于iterable(可迭代的)。

JS的{} + {}与{} + []的结果是什么?

ToPrimitive内部运算

因此,加号运算符只能使用于原始数据类型,那么对于对象类型的值,要如何转换为原始数据类型?下面说明是如何转换为原始数据类型的。

在ECMAScript 6th Edition  #7.1.1,有一个抽象的ToPrimitive运算,它会用于对象转换为原始数据类型,这个运算不只会用在加号运算符,也会用在关系比较或值相等比较的运算中。下面有关于ToPrimitive的说明语法:

ToPrimitive(input,  PreferredType?)input代表代入的值,而PreferredType可以是数字(Number)或字符串(String)其中一种,这会代表”优先的”、”***的”的要进行转换到哪一种原始类型,转换的步骤会依这里的值而有所不同。但如果没有提供这个值也就是预设情况,则会设置转换的hint值为”default”。这个***的转换原始类型的指示(hint值),是在作内部转换时由JS视情况自动加上的,一般情况就是预设值。

而在JS的Object原型的设计中,都一定会有两个valueOf与toString方法,所以这两个方法在所有对象里面都会有,不过它们在转换e有可能会交换被调用的顺序。

当PreferredType为数字(Number)时

当PreferredType为数字(Number)时,input为要被转换的值,以下是转换这个input值的步骤:

  1. 如果input是原始数据类型,则直接返回input。

  2. 否则,如果input是个对象时,则调用对象的valueOf()方法,如果能得到原始数据类型的值,则返回这个值。

  3. 否则,如果input是个对象时,调用对象的toString()方法,如果能得到原始数据类型的值,则返回这个值。

  4. 否则,抛出TypeError错误。

当PreferredType为字符串(String)时

上面的步骤2与3对调.

PreferredType没提供时,也就是hint为”default”时

与PreferredType为数字(Number)时的步骤相同。

数字其实是预设的***类型,也就是说在一般情况下,加号运算中的对象要作转型时,都是先调用valueOf再调用toString。

但这有两个异常,一个是Date对象,另一是Symbol对象,它们覆盖了原来的PreferredType行为,Date对象的预设***类型是字符串(String)。

因此你会看到在一些教程文件上会区分为两大类对象,一类是 Date 对象,另一类叫 非Date(non-date)  对象。因为这两大类的对象在进行转换为原始数据类型时,***类型恰好相反。

模拟代码说明

a + b:     pa = ToPrimitive(a)     pb = ToPrimitive(b)       if(pa is string || pb is string)        return concat(ToString(pa), ToString(pb))     else        return add(ToNumber(pa), ToNumber(pb))

JS对于Object与Array的设计

在JS中所设计的Object纯对象类型的valueOf与toString方法,它们的返回如下:

valueOf方法返回值: 对象本身。(所以ToPrimitive***要返回toString的值了)

toString方法返回值: “[object Object]”字符串值,不同的内建对象的返回值是”[object  type]”字符串,”type”指的是对象本身的类型识别,例如Math对象是返回”[object  Math]”字符串。但有些内建对象因为覆盖了这个方法,所以直接调用时不是这种值。(注意:  这个返回字符串的前面的”object”开头英文是小写,后面开头英文是大写)

一元正号(+),具有让***类型(也就是hint)设置为数字(Number)的功能,所以可以强制让对象转为数字类型,一般的对象会转为:

这里***类型其实本身就是数字,+让toString输出的字符串再强转了一次。

> +{} //相当于 +"[object Object]" NaN

当然,对象的这两个方法都可以被覆盖,你可以用下面的代码来观察这两个方法的运行顺序,下面这个都是先调用valueOf的情况:

let obj = {   valueOf: function () {       console.log('valueOf');       return {}; // object   },   toString: function () {       console.log('toString');       return 'obj'; // string   } } console.log(1 + obj);  //valueOf -> toString -> '1obj' console.log(+obj); //valueOf -> toString -> NaN console.log('' + obj); //valueOf -> toString -> 'obj'

实例

基本类型间运算

字符串 + 其他原始类型字符串在加号运算有***的优先运算

> '1' + 123 "1123"   > '1' + false "1false"   > '1' + null "1null"   > '1' + undefined "1undefined"

数字 + 其他的非字符串的原始数据类型数字为优先

> 1 + true //true转为1, false转为0 2   > 1 + null //null转为0 1   > 1 + undefined //null转为NaN NaN

数字/字符串以外的原始数据类型作加法运算就是转为数字再运算

> true + true 2   > true + null 1   > undefined + null NaN

对象类型间运算

  • 空数组 + 空数组

> [] + []  ""

两个数组相加,依然按照valueOf ->  toString的顺序,但因为valueOf是数组本身,所以会以toString的返回值才是原始数据类型,也就是空字符串,所以这个运算相当于两个空字符串在相加,依照加法运算规则第2步骤,是字符串连接运算(concatenation),两个空字符串连接***得出一个空字符串。

  • 空对象 + 空对象

特别注意: {} + {}在不同的浏览器有不同结果

如果在***个(前面)的空对象加上圆括号(()),这样JS就会认为前面是个对象,就可以得出同样的结果:

> ({}) + {} "[object Object][object Object]"

注: 上面说的行为这与加号运算的***个(前面)的对象字面值是不是个空对象无关,就算是里面有值的对象字面,例如{a:1, b:2},也是同样的结果。

  • Date对象

> 1 + (new Date())  > "1Sun Nov 27 2016 01:09:03 GMT+0800 (CST)"

要得出Date对象中的valueOf返回值,需要使用一元加号(+),来强制转换它为数字类型,例如以下的代码:

> +new Date()  1480180751492

总结

解构赋值产生的问题

> {name: 1}['name'] = '2' {name: 1}['name'] = '2'           ^^^^^^ SyntaxError: Invalid destructuring assignment target

上述错误。

> {name: 1}[name] = '2'  '2'

{name: 1}[name]相当于{name: 1};[name]。解构赋值成功。

{}问题

> var name = 'test' > {[name]:1} Object {1: 1} > {[name]:1};[name] = '1' VM174:1 Uncaught SyntaxError: Unexpected token :

上述错误其实是由于,{[name]:1}中{}是表达式,返回对象;{[name]:1};[name] =  ‘1’中{}是语句,语句中不允许”[name]:1“,换而言之语句中允许”{name: 1}”写法。

{} + {}

{} + {}的结果是会因浏览器而有不同结果,Chrome(v55)中是object  Object字符串连接,但其它的浏览器则是认为相当于+{}运算,得出NaN数字类型。

{} + []的结果是相当于+[],结果是0数字类型。

Date对象

Date对象上面有提及是***类型为”字符串”的一种异常的对象,这与其他的对象的行为不同(一般对象会先调用valueOf再调用toString),在进行加号运算时时,它会优先使用toString来进行转换,***必定是字符串连接运算(concatenation)

> 1 + (new Date()) > "1Sun Nov 27 2016 01:09:03 GMT+0800 (CST)"

toString()

Object.prototype.toString()才是用来检测变量本身的类型,typeof是检测基本类型,instanceof是检测是否在原型链上。(注意一下Object.prototype.toString与Number.prototype.toString、Array.prototype.toString不同)

> var a = 1 undefined > a.toString() '1' > Number.prototype.toString.call(a) '1' > Object.prototype.toString.call([1, 2]) '[object Array]' > Array.prototype.toString.call([1, 2]) '1,2' > [1, 2].join() '1,2'

toString方法返回值: “[object Object]”字符串值,不同的内建对象的返回值是”[object  type]”字符串,”type”指的是对象本身的类型识别,例如Math对象是返回”[object  Math]”字符串。但有些内建对象因为覆盖了这个方法,所以直接调用时不是这种值。(注意:  这个返回字符串的前面的”object”开头英文是小写,后面开头英文是大写。

> Object.prototype.toString.call(null) '[object Null]' > typeof null 'object' > Object.prototype.toString.call(1) '[object Number]'

Number()、String()与Boolean()

常被搞混的是直接使用Number()、String()与Boolean()三个强制转换函数的用法,这与包装对象的用法不同,包装对象是必须使用new关键字进行对象实例化的,例如new  Number(123),而Number(‘123’)则是强制转换其他类型为数字类型的函数。

到此,相信大家对“JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析”有了更深的了解,不妨来实际操作一番吧!这里是编程网网站,更多相关内容可以进入相关频道进行查询,关注我们,继续学习!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

JS语法中由 ++[[]][+[]]+[+[]] = 10引发的问题分析

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

技术分享 | delete 语句引发大量 sql 被 kill 问题分析

作者:王航威有赞 MySQL DBA,擅长分析和解决数据库的性能问题,利用自动化工具解决日常需求。现象某个数据库经常在某个时间点比如凌晨 2 点或者白天某些时间段发出如下报警[Critical][prod][mysql] - 超200 kill SQL/分钟[
技术分享 | delete 语句引发大量 sql 被 kill 问题分析
2017-08-05

JS数组在内存中效率问题的示例分析

这篇文章给大家分享的是有关JS数组在内存中效率问题的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。JS数组我们所熟知的JS数组的结构和其他语言数组结构类似,即物理内存是连续的,所以这也就导致了数组成员移动
2023-06-29

InvocationHandler中invoke()方法的调用问题分析

Java中动态代理的实现,关键就是这两个东西:Proxy、InvocationHandler,下面从InvocationHandler接口中的invoke方法入手,简单说明一下Java如何实现动态代理的。首先,invoke方法的完整形式如下
2023-05-30

GBase8s中唯一索引与非唯一索引问题的示例分析

这篇文章主要为大家展示了“GBase8s中唯一索引与非唯一索引问题的示例分析”,内容简而易懂,条理清晰,希望能够帮助大家解决疑惑,下面让小编带领大家一起研究并学习一下“GBase8s中唯一索引与非唯一索引问题的示例分析”这篇文章吧。唯一索引
2023-06-29

c语言中缓冲区问题的示例分析

这篇文章主要介绍了c语言中缓冲区问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。发现问题你是不是总会出现当你输入的时候(你想的是只输出一个内容),但是最后却输入两
2023-06-25

如何分析C语言在STM32中的内存分配问题

今天就跟大家聊聊有关如何分析C语言在STM32中的内存分配问题,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。01、前言不说废话,先上示例代码uint8_t num_byte[4];u
2023-06-22

C语言一维数组算法问题的示例分析

这篇文章给大家分享的是有关C语言一维数组算法问题的示例分析的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。问题1:将数组中的数逆序存放本题要求编写程序,将给定的n个整数存入数组中,将数组中的这n个数逆序存放, 再按
2023-06-25

MongoDB技术开发中遇到的并发访问问题解决方案分析

MongoDB技术开发中遇到的并发访问问题解决方案分析引言:在当今互联网时代,数据的规模和复杂性不断增长,使得数据库系统面临着越来越严峻的并发访问问题。尤其在大数据领域,MongoDB作为一款非常受欢迎的NoSQL数据库技术,也面临着并发访
2023-10-22

如何处理Go语言中的并发任务的监控和性能分析问题?

如何处理Go语言中的并发任务的监控和性能分析问题?引言:随着互联网的快速发展,我们经常需要处理大量并发的任务,例如同时处理多个请求或者并行计算等。Go语言作为一门高效且简洁的并发编程语言,为我们提供了丰富的工具和库来处理并发任务。然而,在处
2023-10-22

C语言中main()函数参数问题的示例分析

这篇文章主要介绍了C语言中main()函数参数问题的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。#includevoid main(int arg
2023-06-29

编程热搜

目录