关于js类型转换骚操作

本文是lhyt本人原创,希望用通俗易懂的方法来理解一些细节和难点。转载时请注明出处。文章最早出现于本人github

0.前言

js身为一种弱类型的语言,不用像c语言那样要定义int、float、double、string等等数据类型,因为允许变量类型的隐式转换和允许强制类型转换。我们在定义一个变量的时候,就一个var、let、const搞定,不用担心数据的类型。比如常见的字符串拼接,用+号可以实现变量和字符串的拼接。

总的来说,一般的规则是

!后面的字符会被转为换布尔

+后面的字符会被转换为数值(-也是差不多)

[]+后面的字符会被转换为字符串

对于object和number、string、boolean之间的转换关系,这里偷网上一幅图

Object 与Primitive,需要Object转为Primitive

String 与 Boolean,需要两个操作数同时转为Number。

String/Boolean 与 Number,需要String/Boolean转为Number。

undefined 与 null ,和所有其他值比较的结果都是false,他们之间==成立

ToPrimitive是指转换为js内部的原始值,如果是非原始值则转为原始值,调用valueOf()和obj.toString()来实现。valueOf返回对象的值:在控制台,当你定义一个对象按回车,控制台打印的是Object{...},obj.toString()返回对象转字符串的形式,打印的是"[object Object]"

如果参数是Date对象的实例,那么先toString()如果是原始值则返回,否则再valueOf(),如果是原始值则返回,否则报错。

如果参数不是Date对象的实例,同理,不过先valueOf再obj.toString()。

1.奇葩例子

![] //false;

+[] // 0

+![] // 0

[]+[] // ""

{}+{}//"[object Object][object Object]"

{}+[]//0

{a:0}+1 // 1

[]+{}//"[object Object]"

[]+![]//"false"

{}+[]//0

![]+[] // "false"

''+{} //"[object Object]"

{}+'' //0

[]["map"]+[] //"function map() { }"

[]["a"]+[] // "undefined"

[][[]] + []// "undefined"

+!![]+[] //"1"

+!![] //1

1-{} //NaN

1-[] //1

true-1 //0

{}-1 //-1

[]==![] //true

2.从[]==![]开始

大家也可能听说过[]!=[],主要是因为他们是引用类型,内存地址不同所以不相等。那么为什么加了一个!就能等于了?不是内存地址还是不一样吗?

这又引出一个问题,符号的优先度

1. [] ()

2 ++ — ~ !

3 * / %

4 + - +

5 <<  >> 

6 + - +

7 < <= > >=

8 + - +

9 ==  !=  ===  !==

可以看见,!优先度是第二,所以先判断!再判断=

给[]取反,会是布尔值,[]的取反的布尔值就是false

2.1 []的反就是false?

ECMA规范:

非布尔类型转布尔类型:undefined、null 、0、±0、NaN、0长度的字符串=》false,对象=》true

非数字类型转数字类型:undefined=》NaN,null=》0,true=》0,false=》1,字符串:字符串数字直接转数字类型、字符串非数字=》NaN

[]也是对象类型(typeof [] == "object"),转为布尔类型的![]就是false

2.2 等号两边对比

我们知道,在比较类型的时候,先会进行各种各样的类型转换。

从开头的表格可以看见,他们比较的时候都是先转换为数字类型。右边是布尔值false,左边为一个空数组对象,对于左边,先进行P操作(ToPrimitive([])),先执行valueOf([])返回的是[],非原始类型,再

[].toString(),返回的是"",那P操作之后,结果就是""了

最后,左边""和右边false对比,他们再转换为数字,就是0==0的问题了

3.从已有的得到想不到的

3.1 间接获取数组方法

我们知道,数组有自己的一套方法,比如var arr = [1,2];arr.push(1),我们可以写成[1,2].push(1),还可以写成[1,2]['push'](1),那么前面抛出的问题就解决了

[]['push'](1)//[1]

[]["map"] //function map() { [native code] }

[]["map"]+[] // "function map() { [native code] }"

3.2 间接进行下标操作

3.2.1数字的获取

我们可以通过类型转换,获得0和1两个数字,既然能得到这两个数字,那么也可以得到其他的一切数字了:

+[] === 0; +!![] === 1

那么, +!![]+!![] ===2,+((+![])+(+!![])+[]+(+![]))===10(注意:中间没[]的话,就是数字的1+0,结果就是1了,有的话就是'1'+''+'0')

+((+![])+(+!![])+[]+(+![]))-!![] ===9

简直就是无所不能

3.2.2 字符串下标

(![]+[])[+[]] //"f"

(![]+[])[+!![]] // "a"

(![]+[])是"false",其实(![]+[])[+[]] 就相当于"false"[0],第一个字母,就是f

我们就可以从上面的那些获得单词的字符串获得其中的字母了

好了,说道这里,要是谁说前端简单,那就给他一个(![]+[])[+!![]+!![]+!![]] +([]+{})[+!![]+!![]]

4.关于(a==1 && a==2 && a==3)

4.1 ==

近来有人问这个问题(a==1 && a==2 && a==3) 或者(a===1 && a===2 && a===3) 能不能为true?

事实上是可以的,就是因为在==比较的情况下,会进行类型的隐式转换。前面已经说过,如果参数不是Date对象的实例,就会进行类型转换,先valueOf再obj.toString()

所以,我们只要改变原生的valueOf方法就可以达到效果:

var a = {

num: 0,

valueOf: function() {

return this.num += 1

}

};

var eq = (a==1 && a==2 && a==3);

console.log(eq);

每一次进行等号的比较,就会调用一次valueOf方法,自增1,所以能成立。当然,如果换个位置就不行了,var eq = (a==2 && a==1 && a==3);

另外,减法也是同理:

var a = {

num: 4,

valueOf: function() {

return this.num -= 1

}

};

var eq = (a==3 && a==2 && a==1);

console.log(eq);

4.2 ===

如果没有类型转换,===的情况,还是可以的。跑题...

在vue源码实现双向数据绑定中,就利用了defineProperty方法进行观察,观察到视图层的变化并实时反映到model层。

每一次访问对象中的某一个属性的时候,就会调用这个方法定义的对象里面的get方法。每一次改变对象属性的值,就会访问set方法

在这里,我们自己定义自己的get方法:

var b = 1

Object.defineProperty(window, 'a', {

get:function() { return b++; }

})

var s = (a===1 && a===2 && a === 3 )

console.log(s)

每一次访问a属性,a的属性值就会+1,当然还是交换位置就不能为TRUE了


原文来自lhyt的github

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,999评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,102评论 1 302
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,709评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,439评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,846评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,881评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,062评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,783评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,517评论 1 248
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,762评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,241评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,236评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,145评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,941评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,965评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,802评论 2 275

推荐阅读更多精彩内容

  • 第2章 基本语法 2.1 概述 基本句法和变量 语句 JavaScript程序的执行单位为行(line),也就是一...
    悟名先生阅读 4,059评论 0 13
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,105评论 18 139
  • 秋天最好看的风景是,阳光肆意,微风白云,佳人的披肩与短裙,明媚“冻”人,与金黄色的落叶交相辉映,一切都恰好,连心情...
    yaparis阅读 231评论 0 0
  • 阅读时间:2016年1月26日,19:30-21:30,2小时; 阅读书本:《失控》,作者:【美】凯文·凯利;新星...
    时空山庄阅读 107评论 0 1