高级用法 #

深拷贝 #

什么是深拷贝? #

深拷贝是指创建一个对象的完整副本,包括所有嵌套的属性,修改副本不会影响原对象。

text
┌─────────────────────────────────────────────────────────────┐
│                    浅拷贝 vs 深拷贝                          │
├─────────────────────────────────────────────────────────────┤
│                                                              │
│   原对象                                                      │
│   ┌─────────────────────────────────────────┐               │
│   │ { a: 1, b: { c: 2 } }                   │               │
│   └─────────────────────────────────────────┘               │
│                     │                                        │
│         ┌──────────┴──────────┐                             │
│         ▼                     ▼                             │
│   浅拷贝                  深拷贝                              │
│   ┌─────────────────┐   ┌─────────────────┐                 │
│   │ a: 1 (独立)     │   │ a: 1 (独立)     │                 │
│   │ b: ──────────────────►│ b: { c: 2 }    │                 │
│   │    (引用原对象) │   │    (独立副本)   │                 │
│   └─────────────────┘   └─────────────────┘                 │
│                                                              │
└─────────────────────────────────────────────────────────────┘

deepCopy 实现 #

javascript
export const deepCopy = (obj, map) => {
    map = map || new WeakMap();
    
    if (typeof obj !== 'object' || obj === null) {
        return obj;
    }
    
    if (map.has(obj)) {
        return map.get(obj);
    }
    
    let clone;
    if (Array.isArray(obj)) {
        clone = [];
    } else {
        clone = {};
    }
    
    map.set(obj, clone);
    
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clone[key] = deepCopy(obj[key], map);
        }
    }
    
    return clone;
};

使用示例 #

javascript
import { deepCopy } from './utils';

const original = {
    name: 'John',
    age: 25,
    address: {
        city: 'Beijing',
        country: 'China'
    },
    hobbies: ['reading', 'coding']
};

const copy = deepCopy(original);

copy.name = 'Jane';
copy.address.city = 'Shanghai';
copy.hobbies.push('gaming');

console.log(original.name);
console.log(original.address.city);
console.log(original.hobbies);

处理特殊类型 #

javascript
const deepCopyAdvanced = (obj, map = new WeakMap()) => {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }
    
    if (map.has(obj)) {
        return map.get(obj);
    }
    
    if (obj instanceof Date) {
        return new Date(obj);
    }
    
    if (obj instanceof RegExp) {
        return new RegExp(obj.source, obj.flags);
    }
    
    if (obj instanceof Map) {
        const clone = new Map();
        map.set(obj, clone);
        obj.forEach((value, key) => {
            clone.set(deepCopyAdvanced(key, map), deepCopyAdvanced(value, map));
        });
        return clone;
    }
    
    if (obj instanceof Set) {
        const clone = new Set();
        map.set(obj, clone);
        obj.forEach(value => {
            clone.add(deepCopyAdvanced(value, map));
        });
        return clone;
    }
    
    if (Array.isArray(obj)) {
        const clone = [];
        map.set(obj, clone);
        obj.forEach((item, index) => {
            clone[index] = deepCopyAdvanced(item, map);
        });
        return clone;
    }
    
    const clone = {};
    map.set(obj, clone);
    
    Object.keys(obj).forEach(key => {
        clone[key] = deepCopyAdvanced(obj[key], map);
    });
    
    Object.getOwnPropertySymbols(obj).forEach(sym => {
        clone[sym] = deepCopyAdvanced(obj[sym], map);
    });
    
    return clone;
};

深合并 #

什么是深合并? #

深合并是指递归地合并两个或多个对象,嵌套对象也会被合并而不是覆盖。

deepMerge 实现 #

javascript
const isObject = (obj) => {
    return obj !== null && typeof obj === 'object' && !Array.isArray(obj);
};

export const deepMerge = (a, b) => {
    const merged = { ...a };
    
    for (const key in b) {
        if (b.hasOwnProperty(key)) {
            const aVal = a[key];
            const bVal = b[key];
            
            if (isObject(aVal) && isObject(bVal)) {
                merged[key] = deepMerge(aVal, bVal);
            } else {
                merged[key] = bVal;
            }
        }
    }
    
    return merged;
};

使用示例 #

javascript
import { deepMerge } from './utils';

const defaults = {
    theme: 'light',
    language: 'zh-CN',
    notifications: {
        email: true,
        push: true,
        sound: false
    },
    privacy: {
        profile: 'public',
        activity: 'private'
    }
};

const userSettings = {
    theme: 'dark',
    notifications: {
        email: false
    }
};

const merged = deepMerge(defaults, userSettings);

console.log(merged);

多对象合并 #

javascript
const deepMergeMultiple = (...objects) => {
    return objects.reduce((result, obj) => deepMerge(result, obj), {});
};

const config = deepMergeMultiple(
    { a: 1, b: { x: 1 } },
    { b: { y: 2 }, c: 3 },
    { d: 4, b: { z: 3 } }
);

console.log(config);

其他实用函数 #

extendArray #

扩展数组,将数组重复多次。

javascript
export const extendArray = (arr, multiple) => {
    let result = [];
    for (let i = 0; i < multiple; i++) {
        result = result.concat(arr);
    }
    return result;
};

console.log(extendArray([1, 2, 3], 3));

getCharLength #

计算字符串长度,中文字符算 2 个字符。

javascript
export const getCharLength = (str) => {
    let length = 0;
    for (let i = 0; i < str.length; i++) {
        const charCode = str.charCodeAt(i);
        length += (charCode >= 0x4E00 && charCode <= 0x9FFF) ? 2 : 1;
    }
    return length;
};

console.log(getCharLength('Hello世界'));
console.log(getCharLength('JavaScript'));

filterEmptyRowsAndColumns #

过滤二维数组中的空行和空列。

javascript
export const filterEmptyRowsAndColumns = (data) => {
    const filteredRows = data.filter(row => {
        return row.some(cell => cell !== null && cell !== undefined && cell.toString().trim() !== '');
    });
    
    const transposed = filteredRows[0].map((_, colIndex) => 
        filteredRows.map(row => row[colIndex])
    );
    
    const filteredTransposed = transposed.filter(row => {
        return row.some(cell => cell !== null && cell !== undefined && cell.toString().trim() !== '');
    });
    
    return filteredTransposed[0].map((_, colIndex) => 
        filteredTransposed.map(row => row[colIndex])
    );
};

const data = [
    ['', '', ''],
    ['A', 'B', 'C'],
    ['D', 'E', 'F'],
    ['', '', '']
];

console.log(filterEmptyRowsAndColumns(data));

性能优化 #

1. 防抖 #

javascript
const debounce = (fn, delay) => {
    let timer = null;
    return function(...args) {
        clearTimeout(timer);
        timer = setTimeout(() => {
            fn.apply(this, args);
        }, delay);
    };
};

const handleSearch = debounce((query) => {
    console.log('搜索:', query);
}, 300);

handleSearch('h');
handleSearch('he');
handleSearch('hello');

2. 节流 #

javascript
const throttle = (fn, delay) => {
    let lastTime = 0;
    return function(...args) {
        const now = Date.now();
        if (now - lastTime >= delay) {
            fn.apply(this, args);
            lastTime = now;
        }
    };
};

const handleScroll = throttle(() => {
    console.log('滚动位置:', window.scrollY);
}, 100);

window.addEventListener('scroll', handleScroll);

3. 惰性函数 #

javascript
const getXHR = () => {
    if (window.XMLHttpRequest) {
        return new XMLHttpRequest();
    } else if (window.ActiveXObject) {
        return new ActiveXObject('Microsoft.XMLHTTP');
    }
    return null;
};

const getXHRLazy = (() => {
    let xhr = null;
    return () => {
        if (xhr) return xhr;
        
        if (window.XMLHttpRequest) {
            xhr = new XMLHttpRequest();
        } else if (window.ActiveXObject) {
            xhr = new ActiveXObject('Microsoft.XMLHTTP');
        }
        return xhr;
    };
})();

4. 记忆化 #

javascript
const memoize = (fn) => {
    const cache = new Map();
    return function(...args) {
        const key = JSON.stringify(args);
        if (cache.has(key)) {
            return cache.get(key);
        }
        const result = fn.apply(this, args);
        cache.set(key, result);
        return result;
    };
};

const fibonacci = memoize((n) => {
    if (n <= 1) return n;
    return fibonacci(n - 1) + fibonacci(n - 2);
});

console.log(fibonacci(40));

最佳实践 #

1. 错误处理 #

javascript
const safeExecute = (fn, fallback = null) => {
    try {
        return fn();
    } catch (e) {
        console.error('执行错误:', e);
        return fallback;
    }
};

const result = safeExecute(() => JSON.parse('invalid json'), {});

2. 参数验证 #

javascript
const validate = (value, rules) => {
    for (const rule of rules) {
        if (!rule.test(value)) {
            return { valid: false, message: rule.message };
        }
    }
    return { valid: true };
};

const rules = [
    { test: v => v !== undefined, message: '值不能为空' },
    { test: v => typeof v === 'string', message: '值必须是字符串' },
    { test: v => v.length >= 3, message: '长度至少为3' }
];

console.log(validate('hi', rules));
console.log(validate('hello', rules));

3. 类型检查 #

javascript
const TypeCheck = {
    isString: v => typeof v === 'string',
    isNumber: v => typeof v === 'number' && !isNaN(v),
    isBoolean: v => typeof v === 'boolean',
    isFunction: v => typeof v === 'function',
    isObject: v => v !== null && typeof v === 'object' && !Array.isArray(v),
    isArray: v => Array.isArray(v),
    isDate: v => v instanceof Date,
    isRegExp: v => v instanceof RegExp,
    isPromise: v => v instanceof Promise,
    isEmpty: v => {
        if (v === null || v === undefined) return true;
        if (TypeCheck.isArray(v) || TypeCheck.isString(v)) return v.length === 0;
        if (TypeCheck.isObject(v)) return Object.keys(v).length === 0;
        return false;
    }
};

console.log(TypeCheck.isArray([1, 2, 3]));
console.log(TypeCheck.isEmpty({}));

4. 链式调用 #

javascript
class Chain {
    constructor(value) {
        this.value = value;
    }
    
    map(fn) {
        this.value = fn(this.value);
        return this;
    }
    
    filter(fn) {
        if (Array.isArray(this.value)) {
            this.value = this.value.filter(fn);
        }
        return this;
    }
    
    reduce(fn, initial) {
        if (Array.isArray(this.value)) {
            this.value = this.value.reduce(fn, initial);
        }
        return this;
    }
    
    value() {
        return this.value;
    }
}

const result = new Chain([1, 2, 3, 4, 5])
    .filter(x => x > 2)
    .map(x => x * 2)
    .reduce((sum, x) => sum + x, 0)
    .value();

console.log(result);

总结 #

本指南涵盖了 JavaScript 工具函数的各个方面:

  1. 入门基础:了解工具函数的概念和基本使用
  2. 核心功能:URL 处理、Cookie 操作、日期时间、本地存储
  3. 进阶功能:文件处理、颜色转换、主题管理
  4. 高级扩展:加密哈希、深拷贝、深合并、性能优化

通过学习这些内容,你可以:

  • 编写更简洁、高效的代码
  • 提高开发效率和代码质量
  • 构建自己的工具函数库
  • 解决常见的开发问题

继续实践和探索,将这些知识应用到实际项目中!

最后更新:2026-04-04