你可能不知道的JS

不吃貓的魚發表於2019-02-11

最近讀了Javascript Enlightenment。整體感覺還是比較基礎的。這裡記錄跟擴充套件下其中一些知識點。

Math

JS裡有個不成文的規定,建構函式首字母大寫。所以可能容易讓人產生誤解Math是建構函式。其實Math只是一個簡單的封裝了很多數學相關方法的物件。

console.log(typeof Math); //"object"
console.log(typeof Array); //"function"複製程式碼

Function

構造一個函式例項有2種方法:

  • 函式宣告
function sum(x, y) {
    return x + y;
}
console.log(sum(3,4)); //7複製程式碼
  • 通過建構函式
let multiply = new Function("x", "y", "return x * y;");
console.log(multiply(3,4)); //12複製程式碼

工作中經常會有需要用到call或者apply來切換函式執行上下文的情況。例如:

function print(){
    console.log(this.a);
}

print.call({a: `hello`}); //hello複製程式碼

有些面試題可能會問為啥print上沒有定義call方法,但是print.call()呼叫為啥不會報錯。其實是因為print是Function的一個例項化物件,call方法定義在Function.prototype上,通過原型鏈查詢到的call方法。

陣列判斷

typeof可以用來判斷基礎型別,無法用typeof區分陣列跟物件。

console.log(typeof [1,2]); //object
console.log(typeof {}); //object複製程式碼

可以有下面2種常見的方法區分陣列:

  • 原生API: Array.isArray
console.log(Array.isArray([1,2])); //true複製程式碼
  • toString
console.log(Object.prototype.toString.call([1,2])
            .toLowerCase() === `[object array]`); //true複製程式碼

這裡注意下,我們使用了toString方法,然後用call方法切換toString呼叫時的上下文為我們要進行判斷的陣列。所以有些人會誤以為Object.prototype.toString.call([1,2])跟 [1,2].toString()是等價的。其實不然:

console.log(Object.prototype.toString.call([1,2])); //[object Array]
console.log([1,2].toString()); //1,2複製程式碼

這是因為原型鏈查詢有個就近原則。所以當使用[1,2].toString的時候,查詢到並被使用的是Array.prototype.toString,這個方法覆蓋了Object.prototype.toString。

delete 操作符

delete只會刪除自身屬性。不會刪除原型鏈上的屬性。

let obj = {a: `self`};
Object.prototype.a = `prototype`;
console.log(obj.a); //self
delete obj.a;
console.log(obj.a); //prototype
delete Object.prototype.a;
console.log(obj.a); //undefined複製程式碼

全域性物件

訪問全域性物件有2種方法:

  • 變數方法: 瀏覽器裡用window, Node裡用global
  • 在全域性作用域裡使用 this

當我們訪問一個變數的時候會形成一個作用域鏈。作用域的頂端就是全域性變數(i.e. 全域性物件下的對應變數)。相對應的我們也有全域性函式和全域性屬性。曾經有一段程式碼坑了我下:

console.log(hasOwnProperty); //ƒ hasOwnProperty() { [native code] }複製程式碼

剛開始我以為輸出應該是undefined因為印象中hasOwnProperty並非是全域性函式。通過下面的例子大家可以想下為什麼hasOwnProperty不是全域性函式但是上面的輸出不是undefined ~

Object.prototype.hasOwnProperty.call(window, `encodeURI`); // true
`hasOwnProperty` in window //true
Object.prototype.hasOwnProperty.call(window, `hasOwnProperty`); // false複製程式碼

undefined vs null

undefined代表沒值。有2種情況可能出現沒值。

  • 定義了變數但是未賦值
let s;
console.log(s); //undefined複製程式碼
  • 未定義
let obj1 = {};
console.log(obj1.a); //undefined複製程式碼

null表示有值,null是這個特殊的值。

let obj2 = {a: null};
console.log(obj2.a); //null複製程式碼

如果需要同時過濾undefined跟null的話,可以使用弱等於檢查。

console.log(null == undefined); //true
let arr = [null, undefined, 1];
let fil = arr.filter(it => {
    return it != null;
});
console.log(fil); //[1]複製程式碼

另外undefined其實也是個全域性變數, 但是null確不是。null也不掛載在window下。那麼null是哪來的呢?

window.hasOwnProperty(`undefined`); //true
window.hasOwnProperty(`null`); //false
window.null //undefined複製程式碼

Reference

Javascript Enlightenment

Notice

  • 如果您覺得該Repo讓您有所收穫,請「Star 」支援樓主。
  • 如果您想持續關注樓主的最新系列文章,請「Watch」訂閱

相關文章