// 語法:setTimeout(code, delay, arg1, arg2, ...)
// code: 函數引用或字符串代碼(不推薦字符串)
// delay: 毫秒數
// 返回: timerId (用於 clearTimeout)
const timerId = setTimeout(() => {
console.log('3 秒後執行');
}, 3000);
// 清除定時器
clearTimeout(timerId);
// 語法同 setTimeout,返回 timerId
const intervalId = setInterval(() => {
console.log('每秒執行:', new Date().toLocaleTimeString());
}, 1000);
// 停止
clearInterval(intervalId);
setTimeout 遞歸替代。| 特性 | setTimeout | setInterval |
|---|---|---|
| 執行次數 | 一次 | 無限循環 |
| 間隔精確度 | 單次延遲 | 固定間隔嘗試 |
| 停止方式 | clearTimeout(id) | clearInterval(id) |
| 適用場景 | 防抖、節流、延遲初始化、動畫幀 | 輪詢、心跳、定時刷新 |
遞歸 setTimeout 模擬 setInterval(可動態調整間隔、避免堆積):
function repeat(fn, delay) {
fn();
setTimeout(() => repeat(fn, delay), delay);
}
// 使用
repeat(() => console.log('tick'), 1000);
// 字符串 -> 數字
Number('123'); // 123
parseInt('123px'); // 123 (忽略非數字後綴)
parseFloat('3.14'); // 3.14
+'123'; // 123 (一元加運算符)
// 數字 -> 字符串
String(123); // "123"
(123).toString(); // "123"
123 + ''; // "123" (隱式轉換)
'5' - 2; // 3 (字符串隱式轉數字)
'5' + 2; // "52" (+ 觸發字符串拼接)
true + 1; // 2 (boolean -> number)
null + 1; // 1 (null -> 0)
undefined + 1;// NaN
+ 有字符串則拼接,其餘算術運算符嘗試轉數字。// 函數聲明(提升)
function add(a, b) { return a + b; }
// 函數表達式(不提升)
const multiply = function(a, b) { return a * b; };
// 箭頭函數(ES6,無 this/arguments)
const divide = (a, b) => a / b;
// 立即調用函數表達式 (IIFE)
(function() { console.log('IIFE'); })();
arguments.length 獲取實際傳參數量。function foo(a, b, ...rest) {},rest 為真數組,ES6 標準。function foo(x = 10) {}。// 正確:返回對象字面量
function createUser() {
return { name: 'Tom' }; // 大括號同行
}
// 錯誤:自動分號插入 (ASI) 導致返回 undefined
function createUserBroken() {
return
{ name: 'Tom' }; // 等同於 return; { name: 'Tom' };
}
// 最佳實踐:返回對象時大括號不換行,或使用括號包裹
function createUserSafe() {
return (
{ name: 'Tom' }
);
}
function scopeDemo() {
console.log(x); // undefined (非報錯,因提升聲明)
var x = 10;
if (true) {
var y = 20; // 無塊級作用域
}
console.log(y); // 20 可訪問
}
if/for 內 var 洩露到函數外。{
let a = 1;
const PI = 3.14;
// PI = 3; // TypeError: Assignment to constant variable
}
console.log(a); // ReferenceError: a is not defined
// TDZ 示例
function tdz() {
console.log(x); // ReferenceError (進入 TDZ)
let x = 1;
}
let 可重新賦值,const 綁定不可變(對象/數組內容仍可修改)。{} 內聲明外部不可訪問。var globalVar = 'I am global';
console.log(window.globalVar); // 'I am global'
console.log(this.globalVar); // 'I am global' (全局作用域 this === window)
// 函數聲明也屬性掛載
function foo() {}
console.log(window.foo === foo); // true
閉包 = 函數 + 該函數定義時的詞法環境。內部函數引用外部函數變量,外部函數返回內部函數,變量得以「保活」。
function lazySum(arr) {
return function() {
return arr.reduce((x, y) => x + y, 0);
};
}
const sumFn = lazySum([1,2,3,4,5]);
console.log(sumFn()); // 15 (真正計算發生在調用時)
// 錯誤:所有函數共享同一個 i,最終 i=3
var funcs = [];
for (var i = 1; i <= 3; i++) {
funcs.push(function() { return i * i; });
}
console.log(funcs[0]()); // 16 (非 1)
// 修正 1:IIFE 捕獲當前值
var funcs = [];
for (var i = 1; i <= 3; i++) {
funcs.push((function(n) {
return function() { return n * n; };
})(i));
}
console.log(funcs[0]()); // 1
// 修正 2:let 塊級作用域 (ES6 推薦)
let funcs = [];
for (let i = 1; i <= 3; i++) {
funcs.push(function() { return i * i; });
}
console.log(funcs[0]()); // 1
function createCounter(initial = 0) {
let count = initial;
return {
inc: () => ++count,
dec: () => --count,
get: () => count
};
}
const c1 = createCounter();
c1.inc(); // 1
c1.inc(); // 2
const c2 = createCounter(10);
c2.inc(); // 11
// 外部無法直接訪問 count,實現了私有化
function makePow(exp) {
return function(base) {
return Math.pow(base, exp);
};
}
const square = makePow(2);
const cube = makePow(3);
console.log(square(5)); // 25
console.log(cube(3)); // 27
Math.random(); // [0,1) 隨機數
Math.floor(Math.random() * 10); // 0-9 隨機整數
Math.pow(2, 10); // 1024
Math.sqrt(16); // 4
Math.PI; // 3.14159...
Math.max(1,5,3); // 5
eval('1 + 2'); // 3
// 危險:XSS 攻擊向量、性能差、破壞作用域優化
// 替代方案:JSON.parse、Function 構造器、預定義命令映射表
setTimeout 一次性、setInterval 循環、遞歸 setTimeout 更可控。=== 杜絕隱式比較。var 函數級提升,let/const 塊級 + TDZ,優先用 const。