js string转date_【JS基础】隐式转换(二)

fc4bc2ab0a08ab8fb45e05d672332c97.png

写前感

果然做事要趁早,拖了太久就不想做了,比如说写隐式转换(二)这篇文章。之前想要写的思路时隔几天就逐渐忘记了。

但是做事正所谓要有始有终,如果现在不坚持的话,就和没有做没什么区别了

这篇写什么

  • ==, +, -等运算符涉及的隐式转换
  • valueOf操作
  • 原始值是什么
  • toPrimitive操作

Go!

首先我们今天从一个规范开始。

规范就好像网络小说中的本源法则一样,是构成一切生物的规则。 而js规范就好像我们的本源法则,你也不需要知道为什么会这样,反正他就是这么规定的 ,并且一切生物都是按照这个规则在运转。 所以说规范虽然晦涩难懂,但是就好像本源大道一样,一通百通(虽然我也没有很懂哈哈哈

第一关:加号运算符

规范规定

AdditiveExpression + MultiplicativeExpression这个运算会这样执行,用代码的方式可能会更容易理解

AdditiveExpression + MultiplicativeExpression

// 第一步
const lref = AdditiveExpression
// 第二步
const lval = GetValue(lref)
// 第三步
const rref = MultiplicativeExpression
// 第四步
const rval = GetValue(rref)
// 第五步
const lprim = ToPrimitive(lval)
// 第六步
const rprim = ToPrimitive(rval)

// 第七步:如果此时 Type(lprim)或Type(rprim) 类型为String,返回ToString(lprim)与ToString(rprim)的拼接

// 第八步:返回ToNumber(lprim)和ToNumber(rprim)的结果

其中GetValue和ToPrimitive将在后续解答,目前理解为一个函数即可。

当前总会有那么写个特殊情况,针对这些特殊情况,我们看看了解即可

  1. 有运算数为NaN时,结果为NaN
  2. -Infinity-Infinity,结果为-Infinity(此处补充下:两个正的加起来是Infinity,因为本来就是无穷大了=
  3. Infinity-Infinity,结果为NaN(你以为是0?不你错了
  4. +0+0,结果为+0
  5. -0+0,结果为+0
  6. -0-0,结果为-0
小贴士:此处的Infinity和-Infinity分别是代表正无穷和负无穷

第二关:减号运算符

说了加号运算符,就要说说减号运算符了。不过毕竟是减法,在规则上都是减的,让我们来看看减号运算符的规范吧。

同样的,由于规范的文字描述实在是有点绕,所以这里还是以代码的形式相对直观的展示出来

规范规定:

AdditiveExpression - MultiplicativeExpression

// 还是和加法同样的一到四步,不多bb
const lref = AdditiveExpression
const lval = GetValue(lref)
const rref = MultiplicativeExpression
const rval = GetValue(rref)

// 注意第五和第六步开始出现区别了(加法这里是ToPrimitive哦
const lnum = ToNumber(lval)
const rnum = ToNumber(rval)

// 第七步:将减法运算符作用于ToNumber(lprim)和ToNumber(rprim)

减法这里就明显简单了一些GetValue虽然现在还是不知道,但是ToNumber你还不知道吗?

当然对于可恶的特殊值,也会有一些特殊规则,这里列举一下,可以选择性跳过先哈哈

  1. 有运算数为NaN时,结果为NaN
  2. nfinityInfinity,结果为NaN(并不是0
  3. -Infinity-Infinity,结果为NaN(我还以为会是0
  4. Infinity-Infinity,结果为Infinity(这个类比Infinity加Infinity
  5. -InfinityInfinity,结果为-Infinity(毕竟已经负无穷
  6. +0+0,结果为+0
  7. -0-0,结果为-0
  8. +0-0,结果为+0
  9. 有不是数字的,结果为NaN
一定会有人问, 为什么不提前先解答一下GetValue和toPrimitive呢? ️ 原因其实很简单 如果不抱着点疑问和好奇,开局就给你来这么多晦涩难懂的东西你不就关了这篇文章吗?!而且你会直接看的进去吗!

第三关:ToPrimitive(划重点)

原始值

在介绍ToPrimitive之前首先要介绍原始值的概念,众所周知,在Javascript中一共有两种类型的值

(此处暂不提Symbol

一种是原始值primitives):

  • undefined
  • null
  • boolean
  • number
  • string

另一种就是对象值object):

  • object
  • array
  • function
  • date
  • ...

而ToPrimitive其实就是把对象变成原始值的操作啦~

ToPrimitive,这里其实就是一个js引擎内部的一个函数,这个函数会有两个参数,大概长这样

ToPrimitive(obj, preferredType) // 后面会模拟实现一下

// 其中obj是传过来的值,也就是被转换的对象,必填!
// preferredType则是被希望转换成的类型,默认是空,可以是Number | String

正常的小朋友被此函数调用默认第二个参数是Number,而不正常的小朋友(Date就是你)被此函数调用默认第二个参数则是String

下面我们看看第二个参数为Number和String时的执行有什么不同

首先是ToPrimitive(obj, Number)

  1. obj是原始值,直接返回
  2. 调用obj.valueOf(),如果执行结果是原始值,返回
  3. 调用obj.toString(),如果执行结果是原始值,返回
  4. 实在拿你没办法了,抛异常了!

然后是ToPrimitive(obj, String) 其实和上面一模一样,只是顺序变成了1 3 2 4

由此可见,其实只是先valueOf和先toString的区别了

第四关:valueOf与toString

这时陈明明同学要求:这个toString和valueOf你说说呗。

,没问题

首先,toString()方法可以理解为把你见到的所有东西全部字符串化,我们来试试看

var t1 = 1
t1.toString()   // '1'
var t2 = true
t1.toString()   // 'true'
var t3 = NaN
t3.toString()   // 'NaN'
var t4 = undefined
t4.toString()   // Error,本身就undefined,啥也没有要什么自行车 
var t5 = []
t5.toString()   // '' 这个可以注意下
var t6 = function(){ ... }
t6.toString()   // 'function(){ ... }'

而valueOf呢,就是返回对象的原始值

原始值就是我们上面所说的undefined,null,number,string,boolean

但是这里有三个需要注意一下

var o1 = { name: 'o1' }
o1.valueOf() // {name: 'o1'}

var o2 = [1]
o2.valueOf() // [1]

var o3 = new Date()
o3.valueOf() // 1562982586913

下面我们来试着写一下ToPrimitive()

function ToPrimitive(obj, preferredType) {
  const utils = {
    typeOf: function (obj) {
            return Object.prototype.toString.call(obj).slice(8, -1)
        },
        isPrimitive: function (obj) {
            const type = this.typeOf(obj)
            const primitiveArr = ['Undefined', 'Null', 'Number', 'String', 'Boolean']
            return primitiveArr.indexOf(type) !== -1
        }
  }

    // 先判断是不是原始值
    if (utils.isPrimitive(obj)) {
        return obj.valueOf()
    }

    // Date和preferredType === 'String'是先toString再视返回结果执行valueOf()
    if (utils.typeOf(obj) === 'Date' | preferredType === 'String') {
        const res = obj.toString()
        return utils.isPrimitive(res) ? res : res.valueOf()
    }

    // 是原始值valueOf(), 然后视返回结果执行toString()
    const res = obj.valueOf()
    return utils.isPrimitive(res) ? res : res.toString()
}

ToPrimitive({}) // [object Object]

第五关:思考题目

++[[]][+[]]+[+[]] == 10?

// 这是我的思路:
// 1. 由上节一元运算符+我们可知+[]结果为0,所以化简为:
++[[]][0]+[0]

// 2. [[]][0]可以化简为[],可得:
++[]+[0]

// 3. ++[]为ToPrimitive([])+1,所以可得:
1+[0]

// 4. +[0]相当于[0].valueOf().toString() 最终为'0'(不要以为会变成‘[0]’,我就错在这里了

// 5. 所以结果为 1+‘0’ 返回 ‘10’

‘10’ == 10 // true

++[[]][+[]]+[+[]] == 10 // 判断为true

延伸思考

后续我思考过:ToPrimitive([[]])最后实验发现结果为“” 在测试过[1, [2], [3,[4,{}]]]...之后我发现,最终ToPrimitive其实可以理解为无视数组层级最后都会变成以字符串拼接的平铺方式展示

第六关:== 怎么搞?

先看规范,没错还是规范!

c5d8de763c7dca1e8aa5f0280468b509.png

规范里面写的很清楚,但是把我看吐了。

这里总结概括了一下:

运算x == y时,区分两种情况:

  1. Type(x) == Type(y)
  2. Type(x) != Type(y)

Type(x) == Type(y)时规则总结下来就是:

  • NaN返回false
  • Object返回false
  • 其他均为true
这里的Object包括Array,Function,Date

Type(x) != Type(y)时规则可能比较多:

  • Type(x)为String,长度字符位置都相同返回true,其余false
  • x,y为引用的为同一个对象时返回true
  • Undefined和Null对比是true
  • x,y分别为Number/String时,根据x的类型来判断
  • Object与Number/String比较时,进行ToPrimitive操作后比较
  • 其他全是false

没办法 ‍♂️,这东西我们记住就行了,这就是规范

今日总结

知识点:

  • 加号运算符的运算:先转化原始值,字符串优先,其次Number运算。
  • 减号运算符的运算:直接Number运算,不服的都去NaN。
  • 原始值:Null,Undefined,Number,String,Boolean。
  • ToPrimitive(obj, preferredType):valueOf()和toString(),默认为Number先valueOf(),值为String先toString(),注意Date这个小bitch的特殊情况。
  • valueOf: 不是原始值就该返回啥返回啥,但是还是要注意Date这个小bitch的特殊情况。
  • ==运算符: undefined和null是好兄弟可以等,对象的话每个对象都不一样,除非是同一个引用

作者想说的


这篇可能是我目前内容量最大的一篇Blog了,可能内容不如之前那么通俗易懂,但是很多都是规范性质的(再加上我又比较菜哈哈哈 。
我尽可能把它转化成一些易懂的话分享给大家,参考了篇大神的文章,他写的真的很细致,在此感谢作者。但是他的内容量真的很大很大,所以我觉得可能拆分一下精简一下吸收可能更有效吧。

也是我自己学习的一个历程。

我是想写在文章里的,可是知乎一直删,不知道为什么原文链接疯狂被删,很难受

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值