1. 程式人生 > >【前端面試之道小冊筆記】JS基礎篇No.1

【前端面試之道小冊筆記】JS基礎篇No.1

prim 轉字符串 獲取 筆記 特點 只需要 att -s 沒有

1、數據類型

原始值:boolean、null、undefined、number、string、symbol

2、類型轉換:

轉Boolean

在條件判斷時,除了 undefinednullfalseNaN‘‘0-0,其他所有值都轉為 true,包括所有對象。

對象轉原始類型

對象在轉換類型的時候,會調用內置的 [[ToPrimitive]] 函數,對於該函數來說,算法邏輯一般來說如下:

  • 如果已經是原始類型了,那就不需要轉換了
  • 如果需要轉字符串類型就調用 x.toString(),轉換為基礎類型的話就返回轉換的值。不是字符串類型的話就先調用 valueOf
    ,結果不是基礎類型的話再調用 toString
  • 調用 x.valueOf(),如果轉換為基礎類型,就返回轉換的值
  • 如果都沒有返回原始類型,就會報錯

當然你也可以重寫 Symbol.toPrimitive ,該方法在轉原始類型時調用優先級最高。

let a = {
  valueOf() {
    return 0
  },
  toString() {
    return ‘1‘
  },
  [Symbol.toPrimitive]() {
    return 2
  }
}
1 + a // => 3

四則運算符

加法運算符不同於其他幾個運算符,它有以下幾個特點:

  • 運算中其中一方為字符串,那麽就會把另一方也轉換為字符串
  • 如果一方不是字符串或者數字,那麽會將它轉換為數字或者字符串
1 + ‘1‘ // ‘11‘
true + true // 2
4 + [1,2,3] // "41,2,3"

如果你對於答案有疑問的話,請看解析:

  • 對於第一行代碼來說,觸發特點一,所以將數字 1 轉換為字符串,得到結果 ‘11‘
  • 對於第二行代碼來說,觸發特點二,所以將 true 轉為數字 1
  • 對於第三行代碼來說,觸發特點二,所以將數組通過 toString 轉為字符串 1,2,3,得到結果 41,2,3

另外對於加法還需要註意這個表達式 ‘a‘ + + ‘b‘

‘a‘ + + ‘b‘ // -> "aNaN"

因為 + ‘b‘ 等於 NaN,所以結果為 "aNaN",你可能也會在一些代碼中看到過 + ‘1‘ 的形式來快速獲取 number 類型。

那麽對於除了加法的運算符來說,只要其中一方是數字,那麽另一方就會被轉為數字

4 * ‘3‘ // 12
4 * [] // 0
4 * [1, 2] // NaN

3、this

我們先來看幾個函數調用的場景

function foo() {
  console.log(this.a)
}
var a = 1
foo()

const obj = {
  a: 2,
  foo: foo
}
obj.foo()

const c = new foo()

接下來我們一個個分析上面幾個場景

  • 對於直接調用 foo 來說,不管 foo 函數被放在了什麽地方,this 一定是 window
  • 對於 obj.foo() 來說,我們只需要記住,誰調用了函數,誰就是 this,所以在這個場景下 foo 函數中的 this 就是 obj 對象
  • 對於 new 的方式來說,this 被永遠綁定在了 c 上面,不會被任何方式改變 this

說完了以上幾種情況,其實很多代碼中的 this 應該就沒什麽問題了,下面讓我們看看箭頭函數中的 this

function a() {
  return () => {
    return () => {
      console.log(this)
    }
  }
}
console.log(a()()())

首先箭頭函數其實是沒有 this 的,箭頭函數中的 this 只取決包裹箭頭函數的第一個普通函數的 this。在這個例子中,因為包裹箭頭函數的第一個普通函數是 a,所以此時的 thiswindow。另外對箭頭函數使用 bind 這類函數是無效的。

最後種情況也就是 bind 這些改變上下文的 API 了,對於這些函數來說,this 取決於第一個參數,如果第一個參數為空,那麽就是 window

那麽說到 bind,不知道大家是否考慮過,如果對一個函數進行多次 bind,那麽上下文會是什麽呢?

let a = {}
let fn = function () { console.log(this) }
fn.bind().bind(a)() // => ?

如果你認為輸出結果是 a,那麽你就錯了,其實我們可以把上述代碼轉換成另一種形式

// fn.bind().bind(a) 等於
let fn2 = function fn1() {
  return function() {
    return fn.apply()
  }.apply(a)
}
fn2()

可以從上述代碼中發現,不管我們給函數 bind 幾次,fn 中的 this 永遠由第一次 bind 決定,所以結果永遠是 window

let a = { name: ‘yck‘ }
function foo() {
  console.log(this.name)
}
foo.bind(a)() // => ‘yck‘

以上就是 this 的規則了,但是可能會發生多個規則同時出現的情況,這時候不同的規則之間會根據優先級最高的來決定 this 最終指向哪裏。

首先,new 的方式優先級最高,接下來是 bind 這些函數,然後是 obj.foo() 這種調用方式,最後是 foo 這種調用方式,同時,箭頭函數的 this 一旦被綁定,就不會再被任何方式所改變。

如果你還是覺得有點繞,那麽就看以下的這張流程圖吧,圖中的流程只針對於單個規則。

技術分享圖片

補充思考:call&apply&bind

1、call() 、apply()可以看作是某個對象的方法,通過調用方法的形式來間接調用函數,讓函數在某個指定的對象下執行。bind() 就是將某個函數綁定到某個對象上

2、bind() 方法會返回執行上下文被改變的函數而不會立即執行,而前兩者是直接執行該函數

3、bind雖然只返回一個函數並不調用,但是仍然可以傳參,使用bind()方法使函數擁有預設的初始參數,這些參數會排在最前面,傳給綁定函數的參數會跟在它們後面

技術分享圖片
 1 function list(){
 2     // 讓類數組arguments擁有數組的方法slice,這個函數實現了簡單把類數組轉換成數組
 3     return Array.prototype.slice.call(arguments);
 4 }
 5 
 6 list(1,2,3);//[1,2,3]
 7 
 8 //給list綁定一個預設參數4 
 9 var list1 = list.bind(undefined,4);
10 
11 list1();//[4]
12 
13 list1(1,2,3);//[4,1,2,3]

【前端面試之道小冊筆記】JS基礎篇No.1