JavaScript 簡單/不簡單 (小Tips分享)

東岸往事·發表於2019-03-04

簡單的生活從不簡單
簡單的選擇永遠知易行難

「(英)原文連結」, 我並沒有一字一句的翻譯,新增了一些我平時看到的知識一併分享。

JavaScript 簡單/不簡單 (小Tips分享)
如果你是一個和我一樣才入門的小白,這裡的分享的一些JS技巧和陷阱可以幫助你更好的學習和理解它。

如果你已經是個一言不和就開車的老司機了,那麼也可以再看看,也許這裡有你之前沒關注到的小技巧。

1.你是否嘗試過給numbers型別的陣列排序❓

我們都知道, Javascript 提供了sort函式給我們使用, 那麼我們來排一下

[101,2,5,100].sort()
// [ 100, 101, 2, 5 ] .複製程式碼

是不是和我們期待的不t太一樣

The default sort order is according to string Unicode code points.

預設排序規則是陣列元素 字元 的 Unicode 編碼排序的,也就是說陣列元素會被當做字串,然後按照字串的 Unicode 編碼進行升序排列。

那麼如果我們想按照數字的大小排序,你應該這樣做

[101,2,5,100].sort((a, b) => a - b)
//[2, 5, 100, 101]複製程式碼

附加題(來源知乎)

給定一個List(陣列), 元素都是正整數, 要求返回這些元素組成的最大數;
如[5, 2, 31, 3]則返回53312;

這裡分享一下我的思路:

  • 講陣列進行排序(在地鐵上想到的)
  • 怎麼判斷兩個數的順序的,比如31和3; 那麼我們可以讓它們以字元形式分別進行交叉相加,如'331' 和'313',然後根據字元大小規則進行比對
  • 然後再使用join 函式將陣列組成我們要的結果

我實現的程式碼如下:

[5, 2, 31, 3].sort((a, b) => {
    return ('' + b + a) - ('' + a  + b)  
}).join('')複製程式碼

JavaScript 簡單/不簡單 (小Tips分享)

2. new Date() 非常棒?

new Date()可以這樣玩:

  • 無參呼叫(被當做普通函式使用):返回當前日期和時間。
    new Date()
    Wed Dec 14 2016 02:27:18 GMT+0800 (CST)複製程式碼
  • 一個引數(x): 返回1970-01-01加上x毫秒的時間, 熟悉Unix的朋友都知道
    new Date(1000)
    Thu Jan 01 1970 08:00:01 GMT+0800 (CST)複製程式碼
  • 猜一猜new(1, 1, 1)返回的是什麼?
    答案是: 1901-2-01

JavaScript 簡單/不簡單 (小Tips分享)

new Date(1, 1, 1)
Fri Feb 01 1901 00:00:00 GMT+0800 (CST)複製程式碼
  • 第一個1,代表1901年。

    Integer value representing the year. Values from 0 to 99 map to the years 1900 to 1999

  • 第二個1,代表二月。
    是不是很奇怪,為什麼是二月? (阿 二月,你比一月多一月)
    其實是這樣的,月份索引也是從0開始,但是沒有零月啊, 所以0代表一月,那麼1就是二月咯

    Integer value representing the month, beginning with 0 for January to 11 for December.

  • 第三個1,程式碼月份中的第幾天

於是我試了一下:

 new Date(1, 1, 29)
 Fri Mar 01 1901 00:00:00 GMT+0800 (CST)複製程式碼

不是說好代表一個月的第幾天嗎,怎麼第29號沒了,變成了3月1號,那我生日還過不過阿。
好吧,其實1900年的2月的確沒有29號,因為1900年平年 ?
那麼順手把閏年的公式背一背吧

  • 普通年能被4整除且不能被100整除的為閏年。如2004年就是閏年,1900年不是閏年 世紀年能被400整除的是閏年。如2000年是閏年,1900年不是閏年
function isLeapYear(year) {
  return !(year % (year % 100 ? 4 : 400));
}複製程式碼

3. 為什麼沒有全部替換?

let s = "bob"
const replaced = s.replace('b', 'l')
replaced === "lob" // first match only
s === "bob" // original string is remained unchanged複製程式碼

我們都知道replace方法只會替換第一個,那麼如果我要替換全部呢?

使用帶有/ g的正規表示式:

"bob".replace(/b/g, 'l') === 'lol' // replace all occurences複製程式碼

有空多看看正規表示式,它還有一個外號: 瑞士軍刀;

留個題目(來源DIV.io),大家可以評論答案

將ThisNimojs-JavaScript使用正則替換成 TJhaivsaNSicmroijpst

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]是兩個單獨的陣列。 它們恰好包含相同的值。 它們是不同的引用;

這裡我相信大部分人都是理解的;

主要是基本型別的比較和引用型別的比較的不同;

我們再看多看一個東西: ==

[10] ==  10      // 為 true
[10] === 10      // 為 false

'10' ==  10      // 為 true
'10' === 10      // 為 false

 []  ==  0       // 為 true
 []  === 0       // 為 false

 ''  ==  false   // 為 true 但 true == "a" 為false
 ''  === false   // 為 false複製程式碼

== (或者 !=) 操作在需要的情況下自動進行了型別轉換(隱式強制轉換)。=== (或 !==)操作不會執行任何轉換

隱式強制轉換的規則(來源justjavac):

  • 當 JavaScript 需要一個布林值時(例如:if 語句),隱式轉換為布林:“truthy”和“falsy”
    下面的值被轉換為 false:
    • undefined, null
    • Boolean: false
    • Number: -0, +0, NaN
    • String: ‘’
  • 物件的隱式轉換
    只有在 JavaScript 表示式或語句中需要用到數字或字串時,物件才被隱式轉換。 當需要將物件轉換成數字時,需要以下三個步驟:
    • 呼叫 valueOf()。如果結果是原始值(不是一個物件),則將其轉換為一個數字。
    • 呼叫 toString() 方法。如果結果是原始值,則將其轉換為一個數字。
    • 否則,丟擲一個型別錯誤。
  • 字串的隱式轉換
    • 加運算子+ 因為只要其中一個運算元是字串,那麼它就執行連線字串的操作(而不是加法操作,即使它們是數字)

5.Array 的型別?

typeof {} === 'object'  // true
typeof 'a' === 'string' // true
typeof 1 === number     // true
// But....
typeof [] === 'object'  // true複製程式碼

原作者提供了使用Array.isArray()方法用來檢測陣列型別

這裡多提供幾種

 const arr = ['l', 'o', 'v', 'e']

 // instanceof
 arr instanceof Array

 // constructor
 arr.constructor === Array

 // Object.prototype.toString
 Object.prototype.toString.call(o) === '[object Array]'

 // 結合相容性和穩定性的最終版本

function isArray(arr){
  return Array.isArray ? Array.isArray(arr) : Object.prototype.toString.call(arr) === "[object Array]"
}複製程式碼

6. 又是你! ? 閉包

先看個?:

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複製程式碼

期望輸出的1, 2, 3沒了,全都變成了10;

這裡有倆個解決方案

  • 使用ES6提供的let, 關於let的技巧可以看ES2015相關的介紹,這裡不囉嗦了
  • 使用bind方法
    Greeters.push(console.log.bind(null, i))複製程式碼

當然,還可以使用IIFE的方式,不過這倆種是原作者最喜歡的方式;

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的上下文環境並非dog;

現在我這樣做:

asyncGreet () {
  this.someThingAsync()
  .then(this.greet.bind(this))
}複製程式碼

這樣就確保擁有正確的上下文環境了

當然,你也可以這樣做

class Foo {
  constructor (name) {
    this.name = name
    this.greet = this.greet.bind(this)
  }
}複製程式碼

...好像React的中這種繫結很常見(譯者說的)

如果你熟悉ES2015,那麼你不會忘了它=>, 箭頭函式

asyncGreet () {
  this.someThingAsync()
  .then(() => {
    this.greet()
  })
}複製程式碼

JavaScript 簡單/不簡單 (小Tips分享)

也許有些地方翻譯的不恰當,也許有些觀點可能因為我的知識還不夠豐富導致了錯誤,大家可以指出,我馬上修改。 謝謝大家的觀看;

相關文章