资讯专栏INFORMATION COLUMN

关于js类型转换骚操作

zhangwang / 2948人阅读

摘要:原文来源于我的前言身为一种弱类型的语言,不用像语言那样要定义等等数据类型,因为允许变量类型的隐式转换和允许强制类型转换。

原文来源于我的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 << >>
4 + - +
5 < <= > >=
4 + - +
6 == != === !==

可以看见,!优先度是第二,所以先判断!再判断=
给[]取反,会是布尔值,[]的取反的布尔值就是false

2.1 []的反就是false? ECMA规范:

非布尔类型转布尔类型:undefined、null 、0、±0、NaN、0长度的字符串=》false,对象=》true
非数字类型转数字类型:undefined=》NaN,null=》0,true=》1,false=》0,字符串:字符串数字直接转数字类型、字符串非数字=》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或者tostring方法就可以达到效果:

var a = {
  num: 0,
  valueOf: function() {
    return this.num += 1
  }
};
var eq = (a==1 && a==2 && a==3);
console.log(eq);

//或者改写他的tostring方法 
var num = 0;
Function.prototype.toString = function(){
    return ++num;
}
function a(){}

//还可以改写ES6的symbol类型的toP的方法
var  a = {[Symbol.toPrimitive]: (function (i) { return function(){return  ++i } }) (0)};

每一次进行等号的比较,就会调用一次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了

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94363.html

相关文章

  • js操作骂人不带脏

    摘要:让我们快速的复习一下在中一共有两种类型的值原始值和对象值原始值有布尔值数字还有字符串其他的所有值都是对象类型的值包括数组和函数类型转化先按运算符来分一下类减号,乘号,肯定是进行数学运算,所以操作数需转化为类型。 前言 很多小伙伴们觉得javaScript很简单,下面的这行 javaScript代码可能会让你怀疑人生。 (!(~+[])+{})[--[~+][+[]]*[~+[]] +...

    Sunxb 评论0 收藏0
  • Java 12 操作, String居然还能这样玩!

    摘要:都快要来了,必须跟栈长学起即将发布,新特性必须抢先看栈长之前在技术栈微信公众号分享过已发布,还能这样玩这篇文章,介绍了的新玩法,让大家耳目一新。更多关于的资讯干货教程以及好消息,请关注微信公众号技术栈,第一时间推送。 Java 13 都快要来了,12必须跟栈长学起! Java 13 即将发布,新特性必须抢先看! 栈长之前在Java技术栈微信公众号分享过《Java 11 已发布,Stri...

    whidy 评论0 收藏0
  • 关于++[[]][+[]]+[+[]]

    摘要:前几天李老哥秀了一个中骚操作给我看,即的值是各位也可以看一下卧槽,牛逼啊很好奇,如何得到这个结果,莫名其妙就得到了我第一感觉是不可能啊,可是结果就在那这就要思考了,这个是什么码的骚操作计算得来的数字结果还是字符转化,或是别的什么,它是通过什 前几天李老哥秀了一个JavaScript中骚操作给我看,即++[[]][+[]]+[+[]]的值是10;各位也可以看一下 console.log(...

    BlackMass 评论0 收藏0
  • 99%的人都不知道的pandas操作(一)

    摘要:没错,在中你一样可以这样简单的操作,而不同的是你操作的是一整列的字符串数据。因为对于类型的,字符的操作发生在的非重复值上,而并非原上的所有元素上。下面的这些属性基本都是关于查看和操作数据类型的。 作者:xiaoyu 微信公众号:Python数据科学 知乎:python数据分析师 showImg(https://segmentfault.com/img/remote/146000001...

    Jonathan Shieber 评论0 收藏0
  • 99%的人都不知道的pandas操作(一)

    摘要:没错,在中你一样可以这样简单的操作,而不同的是你操作的是一整列的字符串数据。因为对于类型的,字符的操作发生在的非重复值上,而并非原上的所有元素上。下面的这些属性基本都是关于查看和操作数据类型的。 作者:xiaoyu 微信公众号:Python数据科学 知乎:python数据分析师 showImg(https://segmentfault.com/img/remote/146000001...

    ShevaKuilin 评论0 收藏0

发表评论

0条评论

zhangwang

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<