• 谁说 JavaScript 很简单了?


    转载请注明出处,保留原文链接以及作者信息

    本文介绍了 JavaScript 初学者应该知道的一些技巧和陷阱。如果你是老司机,就当做回顾了,哪里有写的不好的地方欢迎指出。

    1. 你是否尝试过对一个数字数组进行排序呢?

    JavaScript 中的 sort() 默认是按字母排序的。所以比如你这样 [1,2,5,10].sort(),会输出 [1,10,2,5]

    正确的排序可以使用 [1,2,5,10].sort((a, b) => a — b)

    是不是很简单,这个知识点是告诉你第一种方式排序是有问题的。

    2. new Date() 很好用

    new Date() 可以接收:

    • 无参数:返回当前时间;
    • 1 个参数 x:返回 1970 年 1 月 1 日 + x 毫秒时间。Unix 的小伙伴知道为什么是这样;
    • new Date(1,1,1) 返回 1901 年 2 月 1 日:第一个 “1” 代表 1900 年以后的第 1 年;第二个 “1” 代表这一年的第 2 个月(并不是像你想象的那样从 1 月开始);第三个 “1” 代表这个月的第 1 天(这个确实是如你想象的那样从 1 开始)。
    • new Date(2017,1,1) :这并不是表示 1900 + 2017了,它就是表示 2017 年 1 月 1 日。

    3. 替换,实际上并没有替换

    对于原始串不被替换掉,我是双手赞同的,我不喜欢一个函数的输入总是在变化。另外你应该知道 replace 只会替换第一个匹配上的字符。

        let s = "bob"
        const replaced = s.replace('b', 'l')
        replaced === "lob" // 只替换第一个匹配上的
        s === "bob" // 原始串始终没变

    如果你想替换所有的,那就是用正则符 /g

        "bob".replace(/b/g, 'l') === 'lol' // 替换所有串

    4. 小心使用比较

        // These are ok
        'abc' === 'abc' // true
        1 === 1         // true
    
        // These are not
        [1,2,3] === [1,2,3] // false
        {a: 1} === {a: 1}   // false
        {} === {}           // false

    原因:[1,2,3] 和 [1,2,3] 是两个数组,它们只是恰巧值相等罢了,他们的引用是不同的,所以不能用简单的 === 来比较。

    5. 数组不是原始类型

        typeof {} === 'object'  // true
        typeof 'a' === 'string' // true
        typeof 1 === number     // true
        // But....
        typeof [] === 'object'  // true

    想知道你的变量是不是数组,仍然可以使用 Array.isArray(myVar)

    6. 闭包

    这是很出名的一道 JavaScript 面试题:

        const Greeters = []
        for (var i = 0 ; i < 10 ; i++) {
          Greeters.push(function () { return console.log(i) })
        }
    
        Greeters[0]() // 10
        Greeters[1]() // 10
        Greeters[2]() // 10

    你预期的是输出:0,1,2...吗?你知道这是为什么吗?你知道怎么 fix 吗?

    我来提两种可能的解决方案来解决这个问题:

    • 第一种:使用 let,不用 var。Duang!解决了~

    let 和 var 的区别是作用域。var 的作用域是最近的函数块。而 let 的作用域是最近的封闭块。如果两个都是在块外的,那两个都是全局的。最近的封闭块,要比最近的函数块范围小。这里是源码

    • 第二种:使用 bind
        Greeters.push(console.log.bind(null, i))

    还有很多方法可以解决这一问题,这里列出了我个人的两种最优选择。

    7. 聊一聊 bind

    你觉得下面的代码会输出什么?

        class Foo {
          constructor (name) {
            this.name = name
          }
    
          greet () {
            console.log('hello, this is ', this.name)
          }
    
          someThingAsync () {
            return Promise.resolve()
          }
    
          asyncGreet () {
            this.someThingAsync()
            .then(this.greet)
          }
        }
    
        new Foo('dog').asyncGreet()

    给你点提示,你认为是否会抛出异常呢?Cannot read property 'name' of undefined

    原因:greet 没有在恰当的上下文中执行。依旧,有很多种方法解决这个问题。

    • 第一种:我个人比较喜欢如下解决方法。
        asyncGreet () {
          this.someThingAsync()
          .then(this.greet.bind(this))
        }

    这种方式可以保证 greet 是在类已经实例化以后被调用。

    • 第二种:如果你想确保 greet 始终可以正确调用,可以绑定到构造函数中。
        class Foo {
          constructor (name) {
            this.name = name
            this.greet = this.greet.bind(this)
          }
        }
    • 第三种:你还应该知道箭头函数(=>)可以保护上下文,也可以解决这个问题。
        asyncGreet () {
          this.someThingAsync()
          .then(() => {
            this.greet()
          })
        }

    虽然我觉得最后一种解决方案这个例子中很不优雅……

    结束语

    恭喜!到现在你知道了 JavaScript 中的一些坑,和一点技巧。JavaScript 中还有很多知识等待着你去学习,不过起码在这几个问题上,你不会再犯错误了。Cheers! o/

    如果你认为文章中还需要注意什么,或者添加什么,请让我知道


    我最近正在写一本《React.js 小书》,对 React.js 感兴趣的童鞋,欢迎指点

  • 相关阅读:
    100行代码实现了多线程,批量写入,文件分块的日志方法
    阿里云客户端开发技巧
    阿里云客户端的实现(支持文件分块,断点续传,进度,速度,倒计时显示)
    类库间无项目引用时,在编译时拷贝DLL
    数据库-锁的实践
    Node.js学习资料
    文档流转,文档操作,文档归档(一)
    滑动验证码研究-后续
    iTextSharp 116秒处理6G的文件
    在职场中混,"讲演稿"的重要性
  • 原文地址:https://www.cnblogs.com/libin-1/p/6696671.html
Copyright © 2020-2023  润新知