js类型转换的各种玩法

前言

对于object和number、string、boolean之间的转换关系

  • [ ] Object 与Primitive,需要Object转为Primitive
  • [ ] String 与 Boolean,需要两个操作数同时转为Number。
  • [ ] String/Boolean 与 Number,需要String/Boolean转为Number。
  • [ ] undefined 与 null ,和所有其他值比较的结果都是false,他们之间==成立

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

  • [ ] 如果参数是Date对象的实例,那么先toString()如果是原始值则返回,否则再valueOf(),如果是原始值则返回,否则报错。
  • [ ] 如果参数不是Date对象的实例,同理,不过先valueOf再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.从[]==![]开始

我们知道,[]!=[],主要是因为他们是引用类型,内存地址不同所以不相等。那么为什么加了一个!就能划上等于号了

符号的优先度
可以参考mdn上的这个汇总表格: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/Operator_Precedence#Table 可以看见,[]==![]这个情况下先判断!再判断= 给[]取反,会是布尔值,[]的取反的布尔值就是false

2.1 []的反就是false?

常见的一些转换:
非布尔类型转布尔类型:undefined、null 、0、±0、NaN、0长度的字符串=》false,对象=》true 非数字类型转数字类型:undefined=》NaN,null=》0,true=》1,false=》0,字符串:字符串数字直接转数字类型、字符串非数字=》NaN

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

2.2 等号两边对比

我们知道,在比较类型的时候,先会进行各种各样的类型转换。 从开头的表格可以看见,他们比较的时候都是先转换为数字类型。右边是布尔值false,左边为一个空数组对象,对于左边,先进行ToPrimitive操作,先执行valueOf([])返回的是[],非原始类型,再 [].toString(),返回的是"",那ToPrimitive操作之后,结果就是""了 最后,左边""和右边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

那么10-1=9也就来了: +((+![])+(+!![])+[]+(+![]))-!![] ===9 简直就是无所不能

3.2.2 字符串下标

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

(![]+[])是"false",其实(![]+[])[+[]] 就相当于"false"[0],第一个字母,就是f 我们就可以从上面的那些获得单词的字符串获得其中的字母了,比如:(![]+[])[+!![]+!![]+!![]] +([]+{})[+!![]+!![]]

掌握基本套路后,我们可以随心所欲发挥,在浏览器的控制台输入一些符号的组合,然后回车看一下我们写的“密码”会转换成什么

([][[]] + [])[(+!![] + [] + [] + +![] ) >> +!![]] +
$$(‘*‘)[~~[]].nodeName[- ~ -+~[]] +
(this + [])[+!![]+[] + +[] - !!{} - !!{}] +
([]+![])[+!!{} << +!![] -~[]] +
({}+{})[+!![] -~[]]

4. 两个面试题

曾经遇到两个这种类型的面试题:

4.1 (a==1 && a==2 && a==3) 能不能为true

(a==1 && a==2 && a==3)或者(a===1 && a===2 && a===3) 能不能为true? 事实上是可以的,就是因为在==比较的情况下,会进行类型的隐式转换。前面已经说过,如果参数不是Date对象的实例,就会进行类型转换,先valueOfobj.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 a = {
  num: 4,
  valueOf: function() {
    return this.num -= 1
  }
};
var res = (a==3 && a==2 && a==1);
console.log(res);

另外,如果没有类型转换,是 === 的比较,还是可以的。 在vue源码实现双向数据绑定中,就利用了defineProperty方法进行观察数据被改变的时候,触发set。 每一次访问对象中的某一个属性的时候,就会调用这个方法定义的对象里面的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了

4.2 完善Cash打印三个101

要求只能在class里面增加代码:

class Cash {}
const a = new Cash(1)
const b = new Cash(100)
console.log(`${a.add(b)},${Cash.add(a,b)},${new Cash(a+b)}`) // 101,101,101

首先,三个输出结果是以隐式转换的形式出现的,这是关键之处。 a和b都是new出来的对象,由new Cash(a+b)可以看出构造函数传入的也是两个Cash的实例对象。那么new出来的结果肯定不是简简单单的一个object,不然就是被转换成‘[object Object]‘,但是你又不得不以object类型出现,那就只能魔改隐式转换用到的toString和valueOf

class Cash {
    constructor (a) {
        this.m = a // 缓存真正的值
        this.valueOf = function () {
            console.log(‘value‘)
            return a
        }
    }

    add ($) { // a.add(b)
        return this.m + $
    }

    toString () { // 隐式转换调用
        return this.m
    }

    static add (v1, v2) { //Cash.add
        return v1 + v2
    }
}

最后

然而,实际项目中两个数据作比较的时候,我们尽量不要写甚至完全不要写两个等号,应该写三个等号,而且js也慢慢有向强类型过渡的趋势。

自己是从事了五年的前端工程师,不少人私下问我,2019年前端该怎么学,方法有没有?

没错,年初我花了一个多月的时间整理出来的学习资料,希望能帮助你快速学习前端,拿高薪offer!

如果你依然在编程的世界里迷茫,不知道自己的未来规划,可以加入web前端学习交流群:731771211 里面可以与大神一起交流并走出迷茫。新手可进群免费领取学习资料,看看前辈们是如何在编程的世界里傲然前行!群里不停更新最新的教程和学习方法(进群送web前端系统学习路线,详细的前端项目实战教学视频),有想学习web前端的,或是转行,或是大学生,还有工作中想提升自己能力的,正在学习的小伙伴欢迎加入

点击:加入

原文地址:http://blog.51cto.com/14197670/2352646

时间: 2024-10-30 05:22:58

js类型转换的各种玩法的相关文章

js命名空间的玩法详解

1.首先为什么要用js命名空间          在我们的项目中,如果多个人为同一个页面写js的话,命名冲突就有可能发生,如果所有的函数都是全局的话,如下: a.js中 function com() {   ..... } b.js中 function com() {     ........ } 且一个页面同时引用了这两个js文件,这样我们调用的时候会出问题,可能老是调用到第一个文件里面的函数了,我之前在做一个项目的时候就碰到了这个问题,我自己b.js文件中ajax的响应函数的名字和a.js文

windows下mongodb基础玩法系列二CURD操作(创建、更新、读取和删除)

windows下mongodb基础玩法系列 windows下mongodb基础玩法系列一介绍与安装 windows下mongodb基础玩法系列二CURD操作(创建.更新.读取和删除) 简单说几句 在mongodb中3元素:db(数据库).collection(集合).document(文档) 其中collection类似于数据库中的表,document类似于行,这样一来我们就将内容对比起来记忆学习了. 数据格式 MongoDB documents是BSON格式(一种类json的一种二进制形式的存

腾讯分分彩源码带龙虎和玩法自言自语Spring依赖注入(XML配置)

至于基于XML依赖注入的过程,首先要找一个比较合适的入口,那就是getBean.那么具体是怎么实现的呢?首先写个测试方法: ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("application-common.xml","application-beans.xml","application_jdbc.xml");Object obj = app.g

移动端触摸滑动插件Swiper使用指南极吉林快三带红黑玩法

首先我们需要下载Swiper的相关文件:吉林快三带红黑玩法 下载地址 QQ2952777280 我们可以直接从Github代码仓库中下载. 或者通过Bower下载: $ bower install swiper或者使用Atmosphere将Swiper制作成Meteor包: $ meteor add nolimits4web:swiper或者使用NMP(JavaScript包管理工具)下载: $ npm install swiper下载压缩包后解压,我们需要用到的js文件和css文件都在dist

夺命雷公狗—玩转SEO---71---百度平台与统计工具的玩法

百度站长平台地址是:https://ziyuan.baidu.com 链接提交,大家可以参考:https://ziyuan.baidu.com/linksubmit/index   这里面有详细的玩法~~! 移动适配 这里面值是适用  独立网站(如:  m.baidu.com)   如果  自适应的网站   而且匹配规则尽量规定出来即可~ ~! MIP&AMP 也是针对独立手机站(如:m.baidu.com)的,自适应站点不适应.对移动端网站加速还是有一点小作用而已,因为有一个算法(闪电算法)所

【精品】北京赛车计划冠军定位玩法技巧

車車是一種投資,我們的目標是:細水長流,見好就收,不求日金千金,只求長期穩定!許多人賠本的原因:1. 資金不足,卻大把下注,跟到第4期不出,錢不夠了,心慌了.有人孤注一擲,衝到第5期中了,嚇的半死.有人不敢跟,第5期出號了,氣死, 然後再跟新計劃,沒錢了,郁悶死.這兩種做法都不對,既然是以投資的心態做事,就應該計劃好翻倍的本錢,做到99%的穩賺,狀況不對就要及時止損. 看著連續中,就是不敢跟,最後咬牙跟了,馬上挂了.于是開始哭,我運氣咋這麽差.不買就中,一買就挂.相反,有些人專門等挂,一挂就上,

Aircrack除破解WiFi密码外的趣味玩法

Aircrack这种屌爆了的攻击测试套件在网上居然只有用它破解WiFi密码的教程,在这里我来扒个冷门,介绍下这款杀器的其他一些有趣的玩法. 0×00:首先你需要一张usb无线网卡 ifconfig查看可以正常识别,如果不行看这里. 0×01:干坏或者不坏的事情前先修改MAC ifconfig [INTERFACE] down#关闭网卡 #[INTERFACE]是指你的无线网卡,一般为wlan0,下不再说明 macchanger -m [MAC] [INTERFACE]#修改MAC,[MAC]是你

关于摇红包 | 必须知道的几种玩法

逢年过节,搞活动 微信红包,摇一摇 佰睿科技摇摇啦应用平台提供各种摇红包玩法 [玩法一]:摇一摇红包 功能简介:这种玩法与16年春节微信官方搞的摇红包活动功能一样,采用ibeacon蓝牙技术,通过"微信摇一摇周边"入口参与活动,用户打开手机蓝牙,摇一摇即可领取现金红包并且可以强制/默认用户关注公众号,所获得的红包金额直接转入用户零钱包,支持设置固定/随机金额红包,可限定参与活动用户,支持领取红包后自定义广告跳转,可设定中奖概率. 功能特点:优化了用户操作层级,红包金额直接转入用户零钱包

黑客玩法,插上你的专有U盘才能开机

这个玩法的效果是这样的: 1.插上你的专有U盘,按电脑开机按钮,电脑正常启动运行: 2.如果不插专有优U盘,按电脑开机按钮,进入桌面后1秒钟电脑自动关机,无法使用.也就是说,没有优U盘将无法使用你的电脑. 下面教你如何实现上面的玩法: 第一步:在自己的U盘(假设是F盘)里,新建一个文本文件,内容可以为空,另存为"密码U盘.txt"文件. 第二步:在电脑的D盘里,新建一个文本文件,编辑该文本文件,文本文件内容如下: @echo off if not exist F:\密码U盘.txt s