• JS探秘——那些你理解存在偏差的问题


    Javascript的连续赋值运算

    var a = {n:1};  
    a.x = a = {n:2};  
    alert(a.x); // --> undefined 

    看 jQuery 源码 时发现的这种写法。 以上第二句 a.x = a = {n:2} 是一个连续赋值表达式。 这个连续赋值表达式在引擎内部究竟发生了什么?是如何解释的?

    加一个变量 b,指向 a。

    var a = {n:1};  
    var b = a; // 持有a,以回查  
    a.x = a = {n:2};  
    alert(a.x);// --> undefined  
    alert(b.x);// --> [object Object] 

    实际执行过程:从右到左,a 先被赋值为 {n:2},随后 a.x 被赋值 {n:2}。第一步 a = {n:2} 的 a 指向的是新的对象 {n:2}, 第二步 a.x = {n:2} 中的 a 是 {a:1}。如下所示

                 a.x  =  a  = {n:2}
                  │      │
          {n:1}<──┘      └─>{n:2}

    为什么 ++[[]][+[]]+[+[]] = 10?

    ++[[]][+[]]+[+[]],它相等于:

    ++[[]][+[]]
    +
    [+[]]

    在 JavaScript 里,+ 会把一些字符转化成数字,如 +"" === 0、+[] === 0,因此,我们可以简化一下(++ 比 + 有更高的优先级):

    ++[[]][0]
    +
    [0]

    因为 [[]][0] 的意思是:获取 [[]] 的第一个元素,这就得出了下面的结果:

    • [[]][0] 返回内部数组 ([])。根据语言规范,我们说 [[]][0] === [] 是不正确的,但让我们把这个内部数组称作 A,以避免错误的写法。
    • ++[[]][0] == A + 1, 因为 ++ 的意思是”加一”。
    • ++[[]][0] === +(A + 1);换句话说,你得到的永远是个数值( +1 并不一定得到的是个数值,但 ++ 一定是)。

    我们可以把这一堆代码简化的更清晰。让我们把 A 换回成 [] :

    +([] + 1)
    +
    [0]

    在 JavaScript 里,这也是正确的:[] + 1 === "1",因为 [] == "" (这相当于一个空的数组的内部元素连接),于是:

    +([] + 1) === +("” + 1),并且 
    +("” + 1) === +("1"),并且 
    +("1") === 1 

    让我们再次简化一下:

    1
    +
    [0]

    同样,在 Javascript 里,这是正确的:[0] == "0",因为这是相当于一个有一个元素的数组的内部元素的连接。 各元素会使用,分隔。 当只有一个元素时,你可以推论出这个过程的结果就是它自身的第一个元素。

    所以,最终我们得到 (数字 + 字符串 = 字符串):

    1
    +
    "0"
    === "10" // 耶!

    [1,2] + [3,4]=="1,23,4"

    JavaScript 的 + 运算符有两个目的:

    1. 将两个数相加
    2. 将两个字符串连接

    规范并没有定义 + 运算符在数组上的行为,所以javascript 首先 把数组转换成字符串,然后在字符串上进行 + 运算。

    如果想连接两个数组,可以使用数组的 concat 方法:

    [1, 2].concat([3, 4]) // [1, 2, 3, 4]

    {}+{}等于多少?

    结果为:NaN

    这个问题的原因是,JavaScript 把第一个 {} 解释成了一个空的代码块(code block)并忽略了它。 NaN 其实是表达式 +{} 计算的结果 (+ 加号以及第二个 {})。 你在这里看到的 + 加号并不是二元运算符「加法」,而是一个一元运算符,作用是将它后面的操作数转换成数字,和 Number() 函数完全一样。例如:

    > +"3.65"
    3.65

    以下的表达式是它的等价形式:

    +{}
    Number({})
    Number({}.toString())  // {}.valueOf() isn’t primitive
    Number("[object Object]")
    NaN

    为什么第一个 {} 会被解析成代码块(code block)呢? 因为整个输入被解析成了一个语句:如果左大括号出现在一条语句的开头,则这个左大括号会被解析成一个代码块的开始。 所以,你也可以通过强制把输入解析成一个表达式来修复这样的计算结果: (译注:我们期待它是个表达式,结果却被解析成了语句)

    > ({} + {})
    '[object Object][object Object]'

    {} === {},结果为false

    每个对象都有自己唯一的标识符,因此通过字面量或构造函数创建的对象和任何其他对象都不相等,我们可以通过 === 进行比较。

    {} === {} //false

    对象是通过引用来比较的,只有两个对象有相同的标识,才认为这个对象是相等的。

    var obj = {};
     obj === obj //true

    原始值没有内部标识,原始值是按值比较的: 比较两个原始值的依据是他们的内容,如果两个原始值的内容相同,这认为这两个原始值相同。

    "abc" === "abc" //true

    原始值和它们的包装类型

    原始值类型 boolean, number 以及 string 都有自己对应的包装类型 Boolean, Number 和 String。 包装类型的实例都是对象值,两种类型之间的转换也很简单:

    • 转换为包装类型:new String("abc")
    • 转换为原始类型:new String("abc").valueOf()

    原始值类型以及它们相应的包装器类型有很多不同点,例如:

     typeof "abc" //'string'
     typeof new String("abc") //'object'
     "abc" instanceof String //false
     new String("abc") instanceof String //true
     "abc" === new String("abc") //false
    

    包装类型的实例是一个对象,因此和 JavaScript 和对象一样,包装类型也无法进行值的比较(只能比较引用)。

     var a = new String("abc");
     var b = new String("abc");
     a == b //false(虽然 a 和 b 有相同的内容,但是依然返回 false)
     a == a //true
    

    5.toFixed(3),报错SyntaxError: Unexpected token ILLEGAL

    原始值没有自己的方法

    包装对象类型很少被直接使用,但它们的原型对象定义了许多其对应的原始值也可以调用的方法。 例如,String.prototype 是包装类型 String 的原型对象。 它的所有方法都可以使用在字符串原始值上。 包装类型的方法 String.prototype.indexOf 在字符串原始值上也有,它们并不是两个拥有相同名称的方法,而的的确确就是同一个方法:

     "abc".charAt === String.prototype.charAt
    true
    

    在数字的包装类型 Number 的原型对象有 toFixed 方法,即 Number.prototype.toFixed,但是当我们写如下代码时却发生错误:

     5.toFixed(3)
    SyntaxError: Unexpected token ILLEGAL
    

    此错误是解析错误(SyntaxError),5 后面跟着一个点号(.),这个点被当作了小数点,而小数点后面应该是一个数,以下代码可以正常运行:

     (5).toFixed(3)
    "5.000"
     5..toFixed(3)
    "5.000"
    
  • 相关阅读:
    复制某文件夹及其子文件夹中的一定大小的文件
    一个简单的查询脚本
    写一个交互的脚本
    nginx+php5.6.12+discuz
    curl 错误
    python 交互界面tab补全
    uwsgi.xml
    supervisorctl
    认识nginx配置文件
    nginx+uwsgi+django 配置3
  • 原文地址:https://www.cnblogs.com/MasterYao/p/7810738.html
Copyright © 2020-2023  润新知