js骚操作骂人不带脏

前言

很多小伙伴们觉得javaScript很简单,下面的这行 javaScript代码可能会让你怀疑人生。


(!(~+[])+{})[--[~+""][+[]]*[~+[]] + ~~!+[]]+({}+[])[[~!+[]]*~+[]]

复制代码

小伙伴们学会了,以后遇到一些讲不通道理,让你不开森的人就把这段代码发给他。

那么这段代码为什么会输出sb呢?

其实这段代码考的是js的类型转化的一些基本原理

首先要运用到的第一个知识就是js运算符的优先级,因为这么长一段运算看的人眼花,我们必须得先根据优先级分成n小段,然后再各个击破

1, js运算符的优先级

优先级的排列如下表:

  优先级从高到低:

根据此规则,我们把这一串运算分为以下16个子表达式:

运算符用红色标出,有一点可能大家会意识不到,其实中括号[]也是一个运算符,用来通过索引访问数组项,另外也可以访问字符串的子字符,有点类似charAt方法,如:'abcd'[1] // 返回'b'。而且中括号的优先级还是最高的哦。

接下来需要运用的就是javascript的类型转化知识了,我们先说说什么情况下需要进行类型转化。当操作符两边的操作数类型不一致或者不是基本类型(也叫原始类型)时,需要进行类型转化。

让我们快速的复习一下.在JavaScript中,一共有两种类型的值:原始值(primitives)和对象值(objects).

  • 原始值有:undefined, null, 布尔值(booleans), 数字(numbers),还有字符串(strings).
  • 其他的所有值都是对象类型的值,包括数组(arrays)和函数(functions).

2.类型转化

(1)先按运算符来分一下类:
  • 减号-,乘号*,肯定是进行数学运算,所以操作数需转化为number类型。

  • 加号+,可能是字符串拼接,也可能是数学运算,所以可能会转化为number或string

  • 一元运算,如+[],只有一个操作数的,转化为number类型

(2)下面来看一下转化规则。
(2).1 对于非原始类型的,通过ToPrimitive() 将值转换成原始类型:

  ToPrimitive(input, PreferredType?)

  可选参数PreferredType是Number或者是String。返回值为任何原始值.如果PreferredType是Number,执行顺序如下:

如果input为primitive,返回

  否则,input为Object。调用 obj.valueOf()。如果结果是primitive,返回。

  否则,调用obj.toString(). 如果结果是primitive,返回

  否则,抛出TypeError

  如果 PreferredType是String,步骤2跟3互换,如果PreferredType没有,Date实例被设置成String,其他都是Number

(2).2 通过ToNumber()将值转换为数字

通过ToNumber()把值转换成Number,直接看ECMA 9.3的表格

参数结果
undefinedNaN
null+0
布尔值true被转换为1,false转换为+0
数字无需转换
字符串由字符串解析为数字.例如,"324"被转换为324

如果输入的值是一个对象,则会首先会调用ToPrimitive(obj, Number)将该对象转换为原始值,然后在调用ToNumber()将这个原始值转换为数字.

(2).3 通过ToString()将值转换为字符串

通过ToString()把值转化成字符串, 直接看ECMA 9.8的表格

参数结果
undefined"undefined"
null"null"
布尔值"true" 或者 "false"
数字数字作为字符串,比如. "1.765"
字符串无需转换

如果输入的值是一个对象,则会首先会调用ToPrimitive(obj, String)将该对象转换为原始值,然后再调用ToString()将这个原始值转换为字符串.

规则就这么多,接下来实践一下,根据我们上面划分出的子表达式,一步一步将这个神奇的代码给执行出来。开工~

先看最简单的子表达式16:+[]

  只有一个操作数[],肯定是转化为number了,根据上面的规则2,[]是个数组,object类型,即对象。所以得先调用toPrimitive转化为原始类型,并且PreferredType为number,这个参数表示更“倾向于”转化的类型,这里肯定是number了。然后首先调用数组的valueOf方法,数组调用valueOf会返回自身,如下:   

     这个时候,我们得到一个空串“”,还没有结束,看上面的规则2描述,继续调用toNumber,转化为number类型,如下:   

大功告成!子表达式16转化完毕,+[],最终得到0。

  来看子表达式15:[~+""]

  空串""前面有两个一元操作符,但是操作数还是只有一个,所以,最终要转化为的类型是number。看规则2吧,空串调用toNumber得到0。接下来是~,这是个什么东东呢?它是位运算符,作用可以记为把数字取负然后减一,所以~0就是-1 。

  别忘了,这个子表达式外头还包着中括号,所以最终的值为[-1],即一个数组,里面只有一个元素-1.

  接下来看子表达式13就简单了,把15、16求出来的填进去,就变成了这样:--[-1][0],取数组的第0个元素,然后自减,结果为-2,是不so easy!

  继续往上走,子表达式14: [~+[]]

  其实把15、和16的原理用上就非常明显了,答案[-1]

  继续来求子表达式9,此刻它已变成:-2*[-1],有稍许不一样,不过没关系,我们还是按照规则来,运算符是乘号*,当然是做数学运算,那后面的[-1]就得转化为number,与16的求法类似,过程如下:

  ①调用toPrimitive,发现是object类型

  ②调用valueOf,返回自身[-1]

  ③因为不是原始类型,继续调用toString,返回"-1"

  ④"-1"是原始类型了,然后调用toNumber,返回-1

  ⑤与-2相乘,返回2

  子表达式10:~~!+[],不多说了,答案1. 就是从右往左依次一元计算。

  有了9和10,我们来到了子表达式4,此刻它已经长这样了:2+1, 好,我不多说了。

  继续看表达式7:!(~+[]),~+[]=-1,这个根据上面已经知道了,那!-1是什么呢?这里要说一下这个感叹号,它是逻辑取非的意思,会把表达式转化为布尔类型,转化规则和js的Truthy和Falsy原则是一样的,后面跟数字的,除0以外都为false,后面跟字符串的,除空串以外都为false。这里的!-1当然就是false了。

  接下来这个表达式3:false+{}有点关键。一个布尔加一个对象,那这个{}应该先转化为原始类型,流程如下:

  ①调用toPrimitive,发现是object类型

  ②调用valueOf,返回自身{},   ③不是原始类型,调用toString,返回"[object Object]"

  ④false与"[object Object]"相加,false先转化为字符串"false"

  ⑤相加得结果"false[object Object]"

  知道了表达式3和4,我们就可以来看表达式1了,此时它是这样的:"false[object Object]"[3],因为这个[]可以取字符串的子字符,像charAt一样,所以得到了结果"s"

  经过上面艰难的流程,我们拿到了字符"s",也就是那张图的左半边,剩下的那个"b",相同的原理可以搞出来,我这里就不一一演示了,留给你练练吧~

  回顾一下这个过程其实也不复杂,只是有一些需要重复劳动的,只要你掌握了运算的优先级,能把大串分解成一个个小串,然后运用类型转化的知识挨个处理就搞定了。怎么样,看到这里你还觉得神奇吗?

同样的,中文字符也是由这样组成的,跟英文同样的道理。

参考

www.cnblogs.com/ziyunfei/ar… zhidao.baidu.com/question/43…

<think>好的,用户需要我用通俗的语言解释复杂概念。首先,我需要确定用户可能太理解哪些术语或概念。比如,量子计算、区块链、机器学习这些都可能让非专业人士感到困惑。 接下来,我得用类比或生活中的例子来简化这些概念。比如,区块链可以比作一个公开的账本,每个人都能查看和验证,这样用户更容易理解其透明性和安全性。 然后,避免使用专业术语。如果必须用,就立刻用简单的语言解释。比如,解释机器学习时,可以比喻成教电脑通过例子学习,而是直接编程。 还要检查是否有常见的误解需要澄清。比如,量子计算是简单的“更快”的计算机,而是利用量子力学原理处理信息的同方式。 最后,确保结构清晰,分点说明,每个方法之间换行,符合用户的要求。同时,结尾的相关问题要基于解释过的概念,帮助用户进一步探索。</think>**用生活类比解释复杂概念** 将抽象概念与常见事物关联。例如解释区块链技术,可将其比作"公共记账本":所有人共同维护一本账本,每次交易都需多数人确认才能记录,账本内容无法私自修改。 **拆分核心要素** 把复杂系统分解为基本组件。如解释疫苗工作原理:疫苗是"病毒模仿者"(灭活/减毒病原体)→免疫系统演练识别→产生记忆细胞→遇到真实病毒时快速反应。 **视觉化描述** 用图像辅助理解。描述相对论时空弯曲时,可用床单类比:重物(天体)使床单(时空)凹陷→周围物体沿凹陷轨迹运动,如同被引力吸引。 **数学概念简化示例** 机器学习中的梯度下降算法: 想象在山顶蒙眼下山,每次用脚试探最陡方向(计算梯度)→迈出小步(学习率)→重复直到平地(最小值)。数学表达式简化为: $$w_{new} = w_{old} - \eta \nabla f(w_{old})$$ 其中$\eta$是步长,$\nabla f$是坡度方向 **代码示例说明** 用Python演示递归原理: ```python def 数楼梯(剩余台阶): if 剩余台阶 == 1: return 1 # 最后一步只有1种走法 if 剩余台阶 == 2: return 2 # 最后两步有两种走法 return 数楼梯(剩余台阶-1) + 数楼梯(剩余台阶-2) ``` 该函数计算走到第n个台阶的方法数(每次走1或2阶),体现递归将大问题分解为小问题的特性
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值