✅ 資料型別
typeof
:一元運算子- 檢測基本資料型別和函式型別
- 無法區分
null
和undefined
,typeof null
返回"object"
- 通常較快,因為它是內建的型別檢查機制
instanceof
:二元運算子- 檢測物件是否為特定建構函式的例項
- 不能檢測基本資料型別,只適用於引用型別
- 可能較慢,因為涉及原型鏈的搜尋
Object.protptype.toString.call()
:方法- 檢測所有資料型別
- 可以區分基本資料型別和引用型別
- 可能較慢,因為涉及內部
[[Class]]
屬性的獲取
分類 | 型別 | 說明 | 示例 | typeof | instanceof | Object.prototype.toString.call() |
---|---|---|---|---|---|---|
基本資料型別 | undefined | 未賦值 |
var a;
|
undefined | [object Undefined] | |
string | 字串 |
var a = 'hello';
|
string | [object String] | ||
number | 數字 |
var a = 1;
|
number | [object Number] | ||
boolean | 布林值 |
var a = true;
|
boolean | [object Boolean] | ||
null | 空值 |
var a = null;
|
null | [object Null] | ||
symbol | 符號(ES6) |
var a = Symbol();
|
symbol | [object Symbol] | ||
bigint | 大整數(ES2020) |
var a = 1n;
|
bigint | [object BigInt] | ||
引用資料型別 | object | 物件 |
var a = {};
|
object | Object | [object Object] |
array | 陣列 |
var a = [];
|
object | Array | [object Array] | |
function | 函式 |
var a = function(){};
|
function | Function | [object Function] | |
date | 日期 |
var a = new Date();
|
object | Date | [object Date] | |
regexp | 正則 |
var a = /d{6}/g;
|
object | RegExp | [object RegExp] | |
自定義資料型別 | my | 自定義類 |
class My {};
|
object | My | [object Object] |
✅ 引用型別資料的內建方法
Object
-
Object.assign(target, source1, source2, ...)
:複製所有可列舉屬性的值從一個或多個源物件到目標物件var Alex = { name: "Alex", age: 20 }; var Bob = { name: "Bob", age: 20, gender: "male" }; var result = Object.assign(Bob, Alex); console.log(result); // { name: 'Alex', age: 20, gender: 'male' }
-
Object.create(proto)
:建立一個新物件,使用指定的proto
物件作為原型var proto = { func: function () { console.log(this.value); }, }; var obj = Object.create(proto); obj.value = "hello world"; obj.func(); // hello world
-
Object.entries(obj)
:返回一個給定物件自身的所有可列舉屬性的鍵值對陣列var Alex = { name: "Alex", age: 20 }; console.log(Object.entries(Alex)); // [ [ 'name', 'Alex' ], [ 'age', 20 ] ]
-
Object.fromEntries(iterable)
:將可迭代的鍵值對陣列或Map
物件轉換為一個新的物件var a = [['a', 'b'], [1, 2]] console.log(Object.fromEntries(a)); // { '1': 2, a: 'b' }
-
Object.keys(obj)
:返回一個給定物件自身的所有可列舉屬性鍵的陣列var Alex = { name: "Alex", age: 20 }; console.log(Object.keys(Alex)); // [ 'name', 'age' ]
-
Object.values(obj)
:返回一個給定物件自身的所有可列舉屬性值的陣列var Alex = { name: "Alex", age: 20 }; console.log(Object.values(Alex)); // [ 'Alex', 20 ]
-
Object.freeze(obj)
:凍結一個物件的屬性,使得屬性不可配置,也不可寫 -
Object.isFrozen(obj)
:判斷一個物件是否被凍結var obj = { a: 1 }; Object.freeze(obj); obj.a = 2; console.log(obj); // { a: 1 } obj.b = 2; console.log(obj); // { a: 1 } console.log(Object.isFrozen(obj)); // true
-
Object.seal(obj)
:防止物件新增新屬性或修改現有屬性的可配置性 -
Object.isSealed(obj)
:判斷一個物件是否被密封var obj = { a: 1 }; Object.seal(obj); obj.a = 2; console.log(obj); // { a: 2 } obj.b = 2; console.log(obj); // { a: 2 } console.log(Object.isSealed(obj)); // true
-
Object.defineProperty(obj, prop, descriptor)
:定義一個物件的新屬性或修改現有屬性的特性var obj = {}; Object.defineProperty(obj, 'a', { value: 1, writable: false, // 可寫性 enumerable: true, // 可列舉性 configurable: false, // 可配置性 }); console.log(obj); // { a: 1 } obj.a = 2; console.log(obj); // { a: 1 }
-
Object.defineProperties(obj, props)
:定義一個物件的多個新屬性或修改現有屬性的特性var obj = {}; Object.defineProperties(obj, { a: { value: 1, writable: false, }, b: { value: 2, writable: true, }, }); console.log(obj.a, obj.b); // 1 2 obj.a = 2; obj.b = 3; console.log(obj.a, obj.b); // 1 3
-
Object.is(value1, value2)
:比較兩個值是否相同,類似於===
運算子console.log(Object.is(123, 123)); // true console.log(Object.is(123, "123")); // false
Array
基本操作方法
-
concat(Array)
:連線兩個或多個陣列,返回一個新陣列var a = [1, 2 ,3]; var b = [4, 5, 6]; var c = a.concat(b); console.log(c); // [ 1, 2, 3, 4, 5, 6 ]
-
copyWithin(target[, start[, end]])
:在陣列內,將指定位置的成員複製到其他位置,並返回修改後的陣列target
:從該位置開始替換資料;如果為負數,則表示倒數(下同)start
:從該位置開始讀取資料,預設為 0end
:到該位置前停止讀取資料(不包括該位置),預設為this.length
var a = [0, 1, 2, 3, 4, 5]; a.copyWithin(3, 0, 3); console.log(a); // [ 0, 1, 2, 0, 1, 2 ]
-
entries()
:返回陣列的可迭代物件,包含陣列中每個索引的鍵值對var a = ["a", "b", "c"]; for (var [key, value] of a.entries()) console.log(key, value); /* * 0 a * 1 b * 2 c */
-
fill(value[, start[, end]])
:填充,用一個固定值填充陣列中從開始索引到結束索引內的全部元素var arr1 = new Array(5); arr1.fill(0); console.log(arr1); // [ 0, 0, 0, 0, 0 ] var arr2 = [1, 1, 1, 1]; arr2.fill(0, 1, 3); console.log(arr2); // [ 1, 0, 0, 1 ]
-
filter(fn)
:過濾器,建立一個新陣列,包含透過所提供函式實現的測試的所有元素var a = [1, 2, 3]; console.log(a.filter((value) => value >= 2)); // [ 2, 3 ]
-
find(fn)
:查詢值,返回陣列中滿足提供的測試函式的第一個元素的值var a = [1, 2, 3]; console.log(a.find((value) => value >= 2)); // 2
-
findIndex(fn)
:查詢索引,返回陣列中滿足提供的測試函式的第一個元素的索引var a = [1, 2, 3]; console.log(a.findIndex((value) => value >= 2)); // 1
-
forEach(fn)
:遍歷,對陣列的每個元素執行一次給定的函式var a = [1, 2, 3]; a.forEach((value) => console.log(value)); /* * 1 * 2 * 3 */
-
includes(item)
:判斷一個陣列是否包含一個指定的值var a = [1, 2, 3]; console.log(a.includes(2), a.includes(4)); // true false
-
indexOf(item)
:返回在陣列中可以找到一個給定元素的第一個索引var a = [1, 1, 1]; console.log(a.indexOf(1)); // 0
-
join(separator)
:將陣列的所有元素連線為字串var a = [1, 2, 3]; console.log(a.join(',')); // 1,2,3
-
keys()
:返回陣列的可迭代物件,包含原始陣列的鍵var a = ["a", "b", "c"]; for (let key of a.keys()) console.log(key); /* * 0 * 1 * 2 */
-
lastIndexOf(item)
:返回在陣列中可以找到一個給定元素的最後一個索引var a = [1, 1, 1]; console.log(a.lastIndexOf(1)); // 2
-
map((currentValue[, index[, array]]) => {}[, thisArg])
:對映,建立一個新陣列,其結果是該陣列中的每個元素是呼叫一次提供的函式後的返回值var a = ['a', 'b', 'c']; var b = a.map((value, index) => value + ' ' + index); console.log(b); // [ 'a 0', 'b 1', 'c 2' ]
-
pop()
:尾出棧,刪除陣列的最後一個元素並返回該元素的值var a = [1, 2, 3]; console.log(a.pop()); // 3 console.log(a); // [ 1, 2 ]
-
push(...items)
:尾壓棧,向陣列的末尾新增一個或多元素,並返回陣列新的長度var a = [0, 1]; console.log(a.push(2)); // 3 console.log(a); // [ 0, 1, 2 ]
-
reduce((accumulator, currentValue[, index[, array]]) => {}[, initialValue])
:將陣列元素計算為一個值(從左到右)var a = ["a", "b", "c"]; console.log(a.reduce((acc, cur) => acc + cur, "")); // abc
-
reduceRight((accumulator, currentValue[, index[, array]]) => {}[, initialValue])
:將陣列元素計算為一個值(從右到左)var a = ["a", "b", "c"]; console.log(a.reduceRight((acc, cur) => acc + cur, "")); // cba
-
reverse()
:反轉陣列的元素順序var a = [1, 2, 3]; console.log(a.reverse()); // [ 3, 2, 1 ]
-
shift()
:頭出棧,刪除並返回陣列的第一個元素var a = [1, 2, 3]; console.log(a.shift()); // 1 console.log(a); // [ 2, 3 ]
-
slice([start[, end]])
:切片,選取陣列的一部分,並返回一個新陣列var a = [1, 2, 3]; console.log(a.slice(1, 3)); // [ 2, 3 ]
-
some(fn)
:檢測陣列元素中是否有元素符合指定條件var a = [1, 2, 3]; console.log(a.some((value) => value < 3)); // true console.log(a.some((value) => value > 3)); // false
-
sort(fn)
:對陣列的元素進行排序var a = [2, 1, 3]; console.log(a.sort((a, b) => a - b)); // [ 1, 2, 3 ] console.log(a.sort((a, b) => b - a)); // [ 3, 2, 1 ]
-
splice(start, deleteCount[, item])
:從陣列中新增或刪除元素var a = [1, 2, 3]; a.splice(1, 1, 1); // [ 1, 1, 3 ] console.log(a);
-
toLocaleString()
:返回一個字串表示陣列中的元素var a = [1000, 2, 3]; console.log(a.toLocaleString()); // 1,000,2,3
-
toString()
:返回一個字串,表示指定的陣列及其元素var a = [1000, 2, 3]; console.log(a.toString()); // 1000,2,3
-
unshift(...items)
:頭壓棧,向陣列的開頭新增一個或多元素,並返回新的長度var a = [2, 3]; console.log(a.unshift(1)); // 3 console.log(a); // [ 1, 2, 3 ]
-
values()
:返回一個新的 Array Iterator 物件,該物件包含陣列每個索引的值var a = ["a", "b", "c"]; for (let value of a.values()) console.log(value); /* * a * b * c */
靜態方法
-
Array.from(arrayLike[, mapFn[, thisArg]])
:從類似陣列或可迭代物件建立一個新的陣列例項console.log( Array.from({ 1: "a", 0: "b", 2: "c", length: 3, }) ); // [ 'b', 'a', 'c' ] console.log(Array.from("abc")); // [ 'a', 'b', 'c' ] console.log(Array.from([1, 2, 3], (x) => x + x)); // [ 2, 4, 6 ]
-
Array.isArray()
:檢查一個值是否為陣列console.log(Array.isArray([1, 2, 3])); // true console.log(Array.isArray([])); // true console.log(Array.isArray(new Array())); // true console.log(Array.isArray(Array.prototype)); // true console.log(Array.isArray("abc")); // false console.log(Array.isArray(null)); // false console.log(Array.isArray(undefined)); // false
-
Array.of()
:建立一個具有可變數量引數的新陣列例項console.log(Array.of(undefined, null, 1, "a")); // [ undefined, null, 1, 'a' ]
案例:陣列去重
-
使用雙重迴圈
var array = [1, 2, 2, 3, 4, 4, 5]; for (var i = 0; i < array.length; i++) { for (var j = i + 1; j < array.length; j++) { if (array[i] === array[j]) { array.splice(j, 1); j--; } } } console.log(array);
-
使用
Set
集合資料結構var array = [1, 2, 2, 3, 4, 4, 5]; var result = [...new Set(array)]; console.log(result);
-
使用
Map
雜湊資料結構var array = [ { name: "Alex", age: 20 }, { name: "Bob", age: 25 }, { name: "Charlie", age: 20 }, ]; let map = new Map(); array.forEach((item) => { if (!map.has(item.age)) { map.set(item.age, [item]); } else { map.get(item.age).push(item); } }); let result = {}; for (let [key, value] of map) { result[key] = value; } console.log(result);
-
使用
filter
方法var array = [ { name: "Alex", age: 20 }, { name: "Bob", age: 25 }, { name: "Charlie", age: 20 }, ]; var result = array.filter((item, index, self) => { return self.findIndex((temp) => temp.name === item.name) === index; }); console.log(result);
-
使用
reduce
方法var array = [ { name: "Alex", age: 20 }, { name: "Bob", age: 25 }, { name: "Charlie", age: 20 }, ]; var result = array.reduce(function (acc, curr) { if (!acc[curr.age]) acc[curr.age] = []; acc[curr.age].push(curr); return acc; }, {}); console.log(result);
Date
getDate()
: 返回月份中的第幾天(從 1 到 31)getDay()
: 返回星期幾(0 表示週日,1 表示週一)getFullYear()
: 返回年份getHours()
: 返回小時(從 0 到 23 )getMilliseconds()
: 返回毫秒(0 到 999)getMinutes()
: 返回分鐘(從 0 到 59)getMonth()
: 返回月份(從 0 到 11)getSeconds()
: 返回秒數(從 0 到 59)getTime()
: 返回自1970年1月1日午夜以來的毫秒數getTimezoneOffset()
: 返回UTC時間與本地時間之間的時差,以分鐘為單位now()
: 返回自 1970 年 1 月 1 日午夜以來的毫秒數parse()
: 解析日期字串並返回自 1970 年 1 月 1 日以來的毫秒數setDate()
: 設定月份中的某一天setFullYear()
: 設定日期物件的年份setHours()
: 設定日期物件的小時setMilliseconds()
: 設定日期物件的毫秒數setMinutes()
: 設定日期物件的分鐘數setMonth()
: 設定日期物件的月份setSeconds()
: 設定日期物件的秒數setTime()
: 將日期設定為 1970 年 1 月 1 日之後(之前)的指定毫秒數toDateString()
: 將日期物件的日期部分轉換為可讀字串toISOString()
: 使用 ISO 標準將日期作為字串返回toJSON()
: 以字串形式返回日期,格式為 JSON 日期toLocaleDateString()
: 使用區域設定約定將Date
物件的日期部分作為字串返回toLocaleTimeString()
: 使用區域設定約定將Date
物件的時間部分作為字串返回toLocaleString()
: 使用區域設定約定將Date
物件轉換為字串toString()
: 將Date
物件轉換為字串toTimeString()
: 將Date
物件的時間部分轉換為字串valueOf()
: 返回Date
物件的原始值
RegExp
-
compile()
:(ES6 開始廢棄)重新編譯正規表示式 -
exec()
:執行正規表示式的搜尋,返回第一個匹配結果的陣列var a = 123 console.log(/^\d+$/.exec(a)); // [ '123', index: 0, input: '123', groups: undefined ]
-
test()
:執行正規表示式的搜尋,返回一個布林值,指示是否找到匹配var a = 123 var b = "123" console.log (/^\d+$/.test(a)) // true console.log (/^\d+$/.test(b)) // true
-
toString()
:返回表示正規表示式的字串console.log(/^\d+$/.toString()); // /^\d+$/
-
flags
:返回正規表示式的標誌(修飾符)的字串 -
source
:返回正規表示式的模式文字 -
lastIndex
:設定或返回正規表示式下次匹配的起始索引console.log(/^\d+$/g.flags); // g console.log(/^\d+$/g.source); // ^\d+$ console.log(/^\d+$/g.lastIndex); // 0
✅ 事件物件
event.preventDefault()
:阻止事件的預設行為event.stopPropagation()
:阻止事件繼續在 DOM 樹上冒泡或捕獲,使事件不會傳播到其他層級的元素event.stopImmediatePropagation()
:阻止同一元素上的其他事件處理程式被觸發,即使它們在事件佇列中等待執行event.target
:返回觸發事件的元素,即事件的目標event.currentTarget
:返回繫結事件處理程式的元素,在事件處理程式內部,this
關鍵字通常指向event.currentTarget
event.timeStamp
:返回事件被觸發的時間戳event.isTrusted
:返回一個布林值,指示事件是否由使用者而非指令碼觸發event.type
:返回事件的型別,如click
、keypress
等event.bubbles
:返回一個布林值,指示事件是否會冒泡event.cancelable
:返回一個布林值,指示事件是否可以被取消event.eventPhase
:返回一個整數,表示事件當前處於事件流的哪個階段(捕獲、目標、冒泡)
✅ 原型(proto)與原型鏈
-
原型分隱式原型與顯示原型
var array = new Array(); var implicit = array.__proto__; // 隱式原型 var explicit = Array.prototype; // 顯式原型 console.log(implicit, explicit); console.log(implicit === explicit); // true
- 此時,類例項的隱式原型全等於類的顯式原型
- 隱式原型指向顯式原型
-
原型鏈是指原型中巢狀著原型
var array = new Array(); console.log(array.__proto__); console.log(array.__proto__.__proto__);
-
可以透過
hasOwnProperty()
方法檢視當前例項本身是否具有某個屬性,而非去原型鏈上尋找class Calc { constructor(x, y) { this.x = x; this.y = y; } } var calc = new Calc(1, 2); console.log(calc.hasOwnProperty('x')); // true console.log(calc.hasOwnProperty('z')); // false
✅ 函式
函式型別
-
具名函式:透過
function
關鍵字宣告的,具有函式名,可以在其作用域內的任何地方呼叫function func() {}
-
匿名函式:通常賦值給變數或者作為引數傳遞給其他函式
var func = function () {};
-
箭頭函式:ES6 引入的一種新的函式定義方式,提供了更簡潔的語法,並且在處理
this
時有所不同var func = () => {};
-
生成器函式:可以暫停執行並在之後恢復執行,透過
function*
關鍵字定義,並使用yield
關鍵字返回值function* generator() { yield 1; yield 2; yield 3; } let g = generator(); console.log(g.next().value); // 1 console.log(g.next().value); // 2 console.log(g.next().value); // 3
-
建構函式:用於建立物件例項,通常首字母大寫,並透過
new
關鍵字呼叫function Person(name, age) { this.name = name; this.age = age; } var person = new Person("Alex", 20); console.log(person.name, person.age); // Alex 20
-
立即執行函式:定義後立即執行,常用於建立私有作用域或避免全域性名稱空間汙染
(function (name) { console.log(name); // Alex })("Alex");
-
回撥函式:回撥函式是作為引數傳遞給另一個函式的函式,通常在某個非同步操作完成後被呼叫
function func(callback) { callback("func"); } func((value) => console.log(value)); // func
-
閉包函式:閉包是指有權訪問另一個函式作用域中變數的函式,通常由一個內部函式引用外部函式的變數形成
function outer(outerValue) { return function inner(innerValue) { console.log("outerValue:", outerValue); // outerValue: out console.log("innerValue:", innerValue); // innerValue: in }; } outer("out")("in");
箭頭函式與普通函式的區別
箭頭函式 | 普通函式 | |
---|---|---|
this 繫結 |
不繫結,捕獲上下文的 this 值 |
動態繫結,取決於函式的呼叫方式 |
arguments 物件 |
沒有自身的 arguments 物件可以使用剩餘引數語法 ...args |
有自身的 arguments 物件包含函式呼叫時傳入的所有引數 |
建構函式 | 不可用,不支援 new |
可以,支援 new |
返回值 | 單個表示式時可以直接返回表示式結果 | 必須使用 return 返回 |
super ,new.target |
不支援 | 支援 |
this.arguments |
不支援 | 支援 |
特點 | 快速、簡潔 | 複雜,多場景適用 |
閉包
-
閉包 = 內層函式 + 引用外層函式的變數
-
閉包不一定要有
return
-
當外層函式需要適使用閉包中的變數時,需要
return
-
閉包應用:實現資料私有(舉例:計數)
function func() { let count = 0; return function closure() { count++; console.log("count", count); }; } const res = func(); res(); // count 1 res(); // count 2
- 節流與防抖函式
- Vue 和 React 的 Hooks 鉤子函式
-
-
閉包不一定有記憶體洩漏
- 在上述計數示例中,
count
變數在closure()
中被引用,無法被作為垃圾回收,從而引起記憶體洩漏 - 並非所有記憶體洩漏都需要手動回收
- 在上述計數示例中,
✅ 作用域
全域性作用域
- 可以被區域性作用域遮蔽
- 在瀏覽器環境中,全域性作用域中的變數通常會成為
window
物件的屬性
區域性作用域
- 變數或函式只能在特定的程式碼塊內部被訪問
塊級作用域
- ES6 引入
- 允許在程式碼塊內部宣告變數和函式,這些變數和函式的作用域被限制在相應的程式碼塊內
- 透過
let
和const
關鍵字實現
作用域鏈
- 用於變數解析的機制
- 當在函式內部嘗試訪問一個變數時,如果該變數在當前函式的區域性作用域中沒有找到,直譯器會沿著作用域鏈向上查詢,直至找到該變數或達到全域性作用域
- 確保了變數的私有性和封裝性,防止了變數名稱的衝突
變數提升
-
變數和函式宣告在程式碼執行之前就被移至其作用域的頂部,但變數的初始化操作保留在原位置
-
表現為:在變數宣告之前引用了變數,會得到
undefined
的值,而非報錯function func() { console.log(a); // undefined var a = 1; console.log(a); // 1 console.log(b); // 報錯:ReferenceError let b = 2; console.log(b); // 2 console.log(c); // 報錯:ReferenceError const c = 3; console.log(c); // 3 } func();
-End-