谁说 JavaScript 很简单了?

本文做者:Aurélien Hervé
编译:胡子大哈 javascript

翻译原文:http://huziketang.com/blog/posts/detail?postId=58e06b98a58c240ae35bb8dd
英文链接:Who said javascript was easy ?java

转载请注明出处,保留原文连接以及做者信息react

本文介绍了 JavaScript 初学者应该知道的一些技巧和陷阱。若是你是老司机,就当作回顾了,哪里有写的很差的地方欢迎指出。面试

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

JavaScript 中的 sort() 默认是按字母排序的。因此好比你这样 [1,2,5,10].sort(),会输出 [1,10,2,5]数组

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

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

2. new Date() 很好用

new Date() 能够接收:函数

  • 无参数:返回当前时间;post

  • 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!解决了~

letvar 的区别是做用域。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 感兴趣的童鞋,欢迎指点

相关文章
相关标签/搜索