调皮的Javascript

作者: lanzhiheng | 来源:发表于2016-07-18 21:33 被阅读71次

    最近开始接触前端的东西。不可或缺的是Javascript这门语言。今天遇到了一些比较神奇的事情。表明这门语言要用好并不是那么的容易。

    1. 自动添加分号

    javascript 的分号并不是必须的,不过忽略的话会发生一些比较有趣的事情。
    我在火狐的Firebug里面编写下列代码:

    var x = 3;
    var y = 4;
    x
    ++
    y
    console.log(x);
    console.log(y);
    

    上面代码会被解析成** x; ++y;** 最后打印结果为 3, 5。javascript的解析器貌似会比较人性化地判断哪些地方需要断句才能够让例子跑起来。(注意是跑起来,不一定是正确地跑起来), 再看下面这个例子:

    function pulsOne(x) {
        return x + 1;
    }
    y = plusOne
    (12+22) + 100.toString()
    

    最后结果很奇怪的,代码会被解析成 y = plusOne(12 + 22) + 100.toString(),结果为35100。但是并不是所有的东西都会跟下一行拼接,比如有些关键字:

    function f(x) {
        return
        x
    }
    
    a = f(33)
    

    这个时候我们都期望是33但是结果却是 undefined。表明它遇到意外了。遇到return之后就自动断句了。同类的会自动断句的还有continue, break

    所以我觉得没什么事还是老老实实得加上分号吧,对于代码可读性十分重要。

    2. 小心黑魔法

    我们写代码总是不可避免的需要去排序。我在node交互环境下对数组[1,12,23,4,5]进行排序

     > [1,12,23,4,5].sort()
     [ 1, 12, 23, 4, 5 ]
    

    上面得出的结果很明显不是我们想要的。它这里进行了类型转换。都把我们需要比较的值转换成对应的字符串初始值(toString()处理)然后再进行比较了,所以有了这个坑爹的结果。要解决这个问题。我们需要传入比较函数。

    > [1,12,23,4,5].sort(function(a, b) {return a > b})
    [ 1, 4, 5, 12, 23 ]
    

    这个就是我们想要的结果了。如果我们设定比较函数的话,通过里面的小于号,会对我们需要比较的对象做valueOf()的初始值的转换。就能得到我们想要的结果了。

    3. 隐藏的对象包装

    var s = "test";
    s.len = 4;
    var t = s.len;
    
    

    由上面等式得出的t的结果是undefined,这很让人费解。这里有个javascript的特性叫做包装对象。当字符串s被赋值后进行了s.len = 4的操作。这个时候会将字符串值调用new String(s)来创建一个临时的字符串对象,赋值成功后就会将其销毁。这叫做包装对象。。。。。所以当我们给t赋值的时候对象已经被销毁了。换句话说s.len已经不存在了。所以t的值是undefined

    那我们现在来做一个实验。包装过的字符串跟没有包装过的字符串是否相同?

    > s2 = new String("I Love Ruby")
    [String: 'I Love Ruby']
    > s1 = "I Love Ruby"
    'I Love Ruby'
    > s1 == s2
    true
    > s1 === s2
    false
    

    很明显,他们的原始值(通过toString或者valueOf处理),然而他们本质上(通过===可以对他们的类型加以判断)是不同的。

    4. 函数作用域

    函数作用域问题一直是比较头疼的事情。举一个权威指南里面一个比较经典的例子。它表明javascript的局部变量作用域是函数级别的。并且会有一种看起来声明提前的现象。

    var scope = "global"
    function f() {
        console.log(scope);
        var scope = "local";
        console.log(scope);
    }
    

    我在node里面运行函数f得到的结果是

    > f()
    undefined
    local
    

    神奇吧,首先打印的scope并不是我们期望的global,因为在函数f的作用域里面全局变量被函数内部变量覆盖了。先会引用局部定义的同名变量。所以上面的例子的表现就是如下面这堆代码:

    var scope = "global"
    function f() {
        var scope;
        console.log(scope);
        scope = "local";
        console.log(scope);
    }
    

    相当与我们把声明提前了。然后在后面再对声明的变量进行赋值。这也是Javascript里面比较特殊的地方吧。

    以上都是我今天接触Javascript后发现的一些比较奇怪的事情。《Javascript权威指南》这本书有比较详细的说明,我只是抽取一些我觉得比较特殊的东西来总结一下。希望于我于大家来说都有好处吧。后期会继续跟进相关的话题。

    相关文章

      网友评论

      • 贤独丶:前两天刚到货的《JavaScript高级程序设计》可以说是相当的头疼了🤔🤔🤔
        lanzhiheng:@南山阑珊喝拿铁 都很少看js了:smile:
        贤独丶:@lanzhiheng 慢慢来 你开路
        lanzhiheng:@南山阑珊喝拿铁 那本我还没看过:smile:

      本文标题:调皮的Javascript

      本文链接:https://www.haomeiwen.com/subject/haqmjttx.html