1.2 复杂数据类型

1 阅读8分钟

1.2.1 Object类型

概念解释

  • 定义:键值对的集合,用于存储相关数据和功能
  • 特点:引用类型、可动态添加属性和方法
  • 使用场景:数据封装、配置对象、原型继承

详细说明

1. 对象的创建和基本操作
// 1. 对象创建方式
// 字面量方式
const user1 = {
    name: '张三',
    age: 25,
    sayHi() {
        console.log(`Hi, I'm ${this.name}`);
    }
};

// 构造函数方式
function User(name, age) {
    this.name = name;
    this.age = age;
}
const user2 = new User('李四', 30);

// Object.create方式
const user3 = Object.create(null); // 创建没有原型的对象
const user4 = Object.create(Object.prototype); // 等同于 {}

// 工厂函数方式
function createUser(name, age) {
    return {
        name,
        age,
        sayHi() {
            console.log(`Hi, I'm ${this.name}`);
        }
    };
}
2. 属性描述符和对象特性
// 1. 属性描述符
const person = {};

// 定义属性
Object.defineProperty(person, 'name', {
    value: '张三',
    writable: true,      // 是否可写
    enumerable: true,    // 是否可枚举
    configurable: true   // 是否可配置
});

// 访问器属性
let _age = 25;
Object.defineProperty(person, 'age', {
    get() {
        return _age;
    },
    set(value) {
        if (value < 0) throw new Error('年龄不能为负数');
        _age = value;
    },
    enumerable: true,
    configurable: true
});

// 2. 对象不可变性
const config = {
    apiKey: 'abc123',
    endpoint: 'https://api.example.com'
};

// 冻结对象(最严格)
Object.freeze(config);

// 密封对象(禁止添加/删除属性,但可以修改现有属性)
Object.seal(config);

// 防止扩展(只禁止添加新属性)
Object.preventExtensions(config);

// 检查对象状态
console.log(Object.isFrozen(config));
console.log(Object.isSealed(config));
console.log(Object.isExtensible(config));
3. 对象操作和遍历
// 1. 属性访问和操作
const obj = {
    a: 1,
    b: 2,
    'special-key': 3
};

// 属性访问
console.log(obj.a);             // 点号访问
console.log(obj['special-key']); // 方括号访问

// 属性检查
console.log('a' in obj);              // true
console.log(obj.hasOwnProperty('a')); // true

// 2. 对象遍历方法
// 遍历可枚举属性
for (const key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(`${key}: ${obj[key]}`);
    }
}

// 获取键、值、键值对
console.log(Object.keys(obj));
console.log(Object.values(obj));
console.log(Object.entries(obj));

// 3. 对象合并和复制
// 浅拷贝
const clone1 = Object.assign({}, obj);
const clone2 = { ...obj };

// 深拷贝
function deepClone(obj) {
    if (obj === null || typeof obj !== 'object') return obj;
    
    const clone = Array.isArray(obj) ? [] : {};
    
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clone[key] = deepClone(obj[key]);
        }
    }
    
    return clone;
}
4. 现代JavaScript对象特性
// 1. 对象解构和默认值
const { name, age = 20, address: { city } = {} } = user;

// 2. 对象属性简写
const x = 1, y = 2;
const point = { x, y };

// 3. 计算属性名
const prefix = 'user';
const users = {
    [`${prefix}1`]: '张三',
    [`${prefix}2`]: '李四'
};

// 4. 对象方法简写
const calculator = {
    add(a, b) {
        return a + b;
    },
    subtract(a, b) {
        return a - b;
    }
};

// 5. 可选链操作符
const response = {
    data: {
        user: {
            address: null
        }
    }
};

const city = response?.data?.user?.address?.city ?? 'Unknown';
5. 实际应用模式
// 1. 配置对象模式
function initializeApp(config) {
    const defaultConfig = {
        debug: false,
        timeout: 3000,
        retries: 3
    };
    
    return {
        ...defaultConfig,
        ...config
    };
}

// 2. 私有属性模式(使用闭包)
function createCounter() {
    let count = 0;  // 私有变量
    
    return {
        increment() {
            return ++count;
        },
        decrement() {
            return --count;
        },
        getCount() {
            return count;
        }
    };
}

// 3. 观察者模式
class EventEmitter {
    #listeners = new Map();
    
    on(event, callback) {
        if (!this.#listeners.has(event)) {
            this.#listeners.set(event, new Set());
        }
        this.#listeners.get(event).add(callback);
    }
    
    emit(event, ...args) {
        const callbacks = this.#listeners.get(event);
        if (callbacks) {
            for (const callback of callbacks) {
                callback(...args);
            }
        }
    }
    
    off(event, callback) {
        const callbacks = this.#listeners.get(event);
        if (callbacks) {
            callbacks.delete(callback);
        }
    }
}
6. 性能优化和最佳实践
// 1. 属性访问优化
class UserManager {
    #userCache = new Map();
    
    getUser(id) {
        // 缓存频繁访问的属性
        if (this.#userCache.has(id)) {
            return this.#userCache.get(id);
        }
        
        const user = this.fetchUser(id);
        this.#userCache.set(id, user);
        return user;
    }
}

// 2. 对象池模式
class ObjectPool {
    #available = [];
    #inUse = new Set();
    
    acquire() {
        let obj = this.#available.pop();
        if (!obj) {
            obj = this.createObject();
        }
        this.#inUse.add(obj);
        return obj;
    }
    
    release(obj) {
        if (this.#inUse.delete(obj)) {
            this.resetObject(obj);
            this.#available.push(obj);
        }
    }
    
    createObject() {
        // 创建新对象
    }
    
    resetObject(obj) {
        // 重置对象状态
    }
}

// 3. 属性描述符优化
class ConfigManager {
    #config = {};
    
    constructor(initialConfig) {
        // 一次性定义所有配置项,提高性能
        Object.defineProperties(this.#config, {
            apiKey: {
                value: initialConfig.apiKey,
                writable: false,
                enumerable: true
            },
            debug: {
                value: initialConfig.debug,
                writable: true,
                enumerable: true
            }
            // ... 其他配置项
        });
    }
}

1.2.2 Array类型

概念解释

  • 定义:有序的数据集合
  • 特点:动态长度、支持多种数据类型、丰富的内置方法
  • 使用场景:数据列表、队列/栈、数据处理

详细说明

1. 数组的创建和基本操作
// 1. 创建数组的方式
// 字面量
const arr1 = [1, 2, 3];

// 构造函数
const arr2 = new Array(3);  // 创建长度为3的空数组
const arr3 = new Array(1, 2, 3);  // 创建包含元素的数组

// Array.from
const arr4 = Array.from('hello');  // ['h', 'e', 'l', 'l', 'o']
const arr5 = Array.from({length: 5}, (_, i) => i * 2);  // [0, 2, 4, 6, 8]

// Array.of
const arr6 = Array.of(3);  // [3] 注意与new Array(3)的区别
const arr7 = Array.of(1, 2, 3);  // [1, 2, 3]

// 2. 基本操作
const numbers = [1, 2, 3, 4, 5];

// 访问元素
console.log(numbers[0]);  // 1
console.log(numbers.at(-1));  // 5 (从末尾访问)

// 修改元素
numbers[0] = 10;

// 添加/删除元素
numbers.push(6);         // 末尾添加
numbers.unshift(0);      // 开头添加
const last = numbers.pop();     // 删除并返回最后一个元素
const first = numbers.shift();  // 删除并返回第一个元素
2. 数组高级操作和方法
// 1. 数组转换和操作
const arr = [1, 2, 3, 4, 5];

// 映射转换
const doubled = arr.map(x => x * 2);  // [2, 4, 6, 8, 10]

// 筛选
const evenNumbers = arr.filter(x => x % 2 === 0);  // [2, 4]

// 归约
const sum = arr.reduce((acc, curr) => acc + curr, 0);  // 15
const max = arr.reduce((a, b) => Math.max(a, b));  // 5

// 查找
const found = arr.find(x => x > 3);  // 4
const foundIndex = arr.findIndex(x => x > 3);  // 3

// 检查条件
const hasEven = arr.some(x => x % 2 === 0);  // true
const allPositive = arr.every(x => x > 0);   // true

// 2. 数组切片和连接
const original = [1, 2, 3, 4, 5];

// 切片
const slice1 = original.slice(1, 3);  // [2, 3]
const slice2 = original.slice(-2);    // [4, 5]

// 拼接
const spliced = [...original];
spliced.splice(1, 2, 'a', 'b');  // 返回被删除的元素 [2, 3]
console.log(spliced);  // [1, 'a', 'b', 4, 5]

// 连接
const combined = [0, ...original, 6];  // [0, 1, 2, 3, 4, 5, 6]
3. 数组排序和搜索
// 1. 排序方法
const numbers = [23, 5, 100, 56, 9, 13];
const strings = ['banana', 'apple', 'Cherry', 'date'];

// 基本排序
numbers.sort((a, b) => a - b);  // 升序
numbers.sort((a, b) => b - a);  // 降序

// 自定义排序
strings.sort((a, b) => a.localeCompare(b));  // 考虑大小写的字符串排序

// 2. 高级排序实现
class SortUtils {
    static quickSort(arr) {
        if (arr.length <= 1) return arr;
        
        const pivot = arr[Math.floor(arr.length / 2)];
        const left = arr.filter(x => x < pivot);
        const middle = arr.filter(x => x === pivot);
        const right = arr.filter(x => x > pivot);
        
        return [...this.quickSort(left), ...middle, ...this.quickSort(right)];
    }
    
    static mergeSort(arr) {
        if (arr.length <= 1) return arr;
        
        const mid = Math.floor(arr.length / 2);
        const left = this.mergeSort(arr.slice(0, mid));
        const right = this.mergeSort(arr.slice(mid));
        
        return this.merge(left, right);
    }
    
    static merge(left, right) {
        const result = [];
        let i = 0, j = 0;
        
        while (i < left.length && j < right.length) {
            result.push(left[i] <= right[j] ? left[i++] : right[j++]);
        }
        
        return [...result, ...left.slice(i), ...right.slice(j)];
    }
}
4. 数组性能优化和最佳实践
// 1. 预分配数组长度
const n = 1000000;
const arr = new Array(n);  // 预分配空间

// 2. 使用适当的数组方法
class ArrayOptimization {
    // 错误示例:频繁的数组操作
    static badPractice(arr) {
        // 每次unshift都需要移动所有元素
        for (let i = 0; i < 1000; i++) {
            arr.unshift(i);
        }
    }
    
    // 正确示例:批量操作
    static goodPractice(arr) {
        const temp = new Array(1000);
        for (let i = 0; i < 1000; i++) {
            temp[i] = i;
        }
        return [...temp, ...arr];
    }
    
    // 使用TypedArray提高性能
    static useTypedArray() {
        const int32Arr = new Int32Array(1000);
        const float64Arr = new Float64Array(1000);
        
        return {
            int32Arr,
            float64Arr
        };
    }
}

// 3. 数组去重
class ArrayDeduplication {
    // 使用Set去重
    static usingSet(arr) {
        return [...new Set(arr)];
    }
    
    // 使用Map去重(保留对象引用)
    static usingMap(arr) {
        return Array.from(new Map(arr.map(item => [
            typeof item === 'object' ? JSON.stringify(item) : item,
            item
        ])).values());
    }
}
5. 实际应用场景
// 1. 分页处理
class Pagination {
    static paginate(array, pageSize, pageNumber) {
        return array.slice(
            (pageNumber - 1) * pageSize,
            pageNumber * pageSize
        );
    }
    
    static createPageInfo(array, pageSize) {
        return {
            totalItems: array.length,
            totalPages: Math.ceil(array.length / pageSize),
            hasNextPage: (pageNumber) => 
                pageNumber * pageSize < array.length,
            hasPrevPage: (pageNumber) => pageNumber > 1
        };
    }
}

// 2. 数据转换和处理
class DataProcessor {
    static groupBy(array, key) {
        return array.reduce((groups, item) => {
            const group = groups[item[key]] || [];
            return {
                ...groups,
                [item[key]]: [...group, item]
            };
        }, {});
    }
    
    static flatten(array, depth = 1) {
        return array.reduce((flat, item) => {
            return flat.concat(
                Array.isArray(item) && depth > 0
                    ? this.flatten(item, depth - 1)
                    : item
            );
        }, []);
    }
}

// 3. 缓存系统
class ArrayCache {
    #cache = new Map();
    #maxSize;
    
    constructor(maxSize = 1000) {
        this.#maxSize = maxSize;
    }
    
    set(key, value) {
        if (this.#cache.size >= this.#maxSize) {
            const firstKey = this.#cache.keys().next().value;
            this.#cache.delete(firstKey);
        }
        this.#cache.set(key, value);
    }
    
    get(key) {
        return this.#cache.get(key);
    }
}

1.2.3 Function类型

概念解释

  • 定义:可执行的代码块,也是一种特殊的对象
  • 特点:一等公民、支持闭包、动态this绑定
  • 使用场景:代码复用、回调、面向对象编程、函数式编程

详细说明

1. 函数的创建和基本特性
// 1. 函数声明方式
// 函数声明
function add(a, b) {
    return a + b;
}

// 函数表达式
const subtract = function(a, b) {
    return a - b;
};

// 箭头函数
const multiply = (a, b) => a * b;

// 构造函数(不推荐)
const divide = new Function('a', 'b', 'return a / b');

// 2. 函数参数
function example(required, optional = 'default', ...rest) {
    console.log(required);    // 必需参数
    console.log(optional);    // 可选参数带默认值
    console.log(rest);        // 剩余参数
}

// 3. 函数属性
function greet(name) {
    console.log(`Hello, ${name}!`);
}

console.log(greet.length);     // 1 (参数个数)
console.log(greet.name);       // "greet" (函数名)
console.log(greet.toString()); // 函数源码字符串
2. 闭包和作用域
// 1. 基本闭包
function createCounter() {
    let count = 0;  // 私有变量
    
    return {
        increment() {
            return ++count;
        },
        decrement() {
            return --count;
        },
        getCount() {
            return count;
        }
    };
}

// 2. 模块模式
const calculator = (function() {
    // 私有变量和函数
    let result = 0;
    
    function validate(n) {
        return typeof n === 'number' && !isNaN(n);
    }
    
    // 公共API
    return {
        add(n) {
            if (validate(n)) result += n;
            return this;
        },
        subtract(n) {
            if (validate(n)) result -= n;
            return this;
        },
        getResult() {
            return result;
        }
    };
})();

// 3. 记忆化(缓存)
function 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 memoizedFib = memoize(function fib(n) {
    if (n <= 1) return n;
    return fib(n - 1) + fib(n - 2);
});
3. this绑定和上下文
// 1. this绑定方式
class ThisBindingDemo {
    constructor() {
        this.value = 42;
    }
    
    // 方法中的this
    regularMethod() {
        console.log(this.value);
    }
    
    // 箭头函数中的this
    arrowMethod = () => {
        console.log(this.value);
    }
    
    // 显式绑定示例
    static demonstrateBinding() {
        const obj = { value: 'test' };
        
        function fn() {
            console.log(this.value);
        }
        
        // call方式
        fn.call(obj);  // "test"
        
        // apply方式
        fn.apply(obj, []);  // "test"
        
        // bind方式
        const boundFn = fn.bind(obj);
        boundFn();  // "test"
    }
}

// 2. 上下文保持
class ContextPreservation {
    constructor() {
        this.data = [1, 2, 3];
    }
    
    // 错误示例
    badAsyncOperation() {
        this.data.forEach(function(item) {
            // this已丢失
            setTimeout(function() {
                console.log(this.data); // undefined
            }, 100);
        });
    }
    
    // 正确示例
    goodAsyncOperation() {
        this.data.forEach(item => {
            setTimeout(() => {
                console.log(this.data); // [1, 2, 3]
            }, 100);
        });
    }
}
4. 函数式编程特性
// 1. 高阶函数
class FunctionalProgramming {
    // 函数组合
    static compose(...fns) {
        return fns.reduce((f, g) => (...args) => f(g(...args)));
    }
    
    // 柯里化
    static curry(fn) {
        return function curried(...args) {
            if (args.length >= fn.length) {
                return fn.apply(this, args);
            }
            return (...moreArgs) => curried.apply(this, [...args, ...moreArgs]);
        };
    }
    
    // 偏函数应用
    static partial(fn, ...presetArgs) {
        return function(...laterArgs) {
            return fn.apply(this, [...presetArgs, ...laterArgs]);
        };
    }
}

// 2. 实际应用示例
// 管道操作
const pipe = (...fns) => x => fns.reduce((v, f) => f(v), x);

const processData = pipe(
    x => x * 2,
    x => x + 1,
    x => x.toString()
);

// 函数式数据处理
const users = [
    { id: 1, name: 'John', age: 30 },
    { id: 2, name: 'Jane', age: 25 },
    { id: 3, name: 'Bob', age: 35 }
];

const processUsers = pipe(
    users => users.filter(u => u.age > 25),
    users => users.map(u => u.name),
    names => names.join(', ')
);
5. 性能优化和最佳实践
// 1. 函数性能优化
class FunctionOptimization {
    // 防抖
    static debounce(fn, delay) {
        let timeoutId;
        return function(...args) {
            clearTimeout(timeoutId);
            timeoutId = setTimeout(() => fn.apply(this, args), delay);
        };
    }
    
    // 节流
    static throttle(fn, limit) {
        let inThrottle;
        return function(...args) {
            if (!inThrottle) {
                fn.apply(this, args);
                inThrottle = true;
                setTimeout(() => inThrottle = false, limit);
            }
        };
    }
    
    // 函数重用
    static reuseFunction() {
        // 错误示例
        const badExample = {
            handleClick: () => console.log('clicked'),
            render() {
                return {
                    onClick: () => console.log('clicked') // 每次渲染创建新函数
                };
            }
        };
        
        // 正确示例
        const goodExample = {
            handleClick: () => console.log('clicked'),
            render() {
                return {
                    onClick: this.handleClick // 重用已存在的函数
                };
            }
        };
    }
}

// 2. 异步函数处理
class AsyncFunctionHandling {
    // 异步函数包装器
    static async asyncWrapper(fn) {
        try {
            const result = await fn();
            return [null, result];
        } catch (error) {
            return [error, null];
        }
    }
    
    // 重试机制
    static async retry(fn, attempts = 3, delay = 1000) {
        for (let i = 0; i < attempts; i++) {
            try {
                return await fn();
            } catch (error) {
                if (i === attempts - 1) throw error;
                await new Promise(resolve => setTimeout(resolve, delay));
            }
        }
    }
}
6. 实际应用场景
// 1. 事件系统
class EventSystem {
    #handlers = new Map();
    
    on(event, handler) {
        if (!this.#handlers.has(event)) {
            this.#handlers.set(event, new Set());
        }
        this.#handlers.get(event).add(handler);
        
        // 返回取消订阅函数
        return () => this.off(event, handler);
    }
    
    off(event, handler) {
        const handlers = this.#handlers.get(event);
        if (handlers) {
            handlers.delete(handler);
        }
    }
    
    emit(event, ...args) {
        const handlers = this.#handlers.get(event);
        if (handlers) {
            handlers.forEach(handler => handler(...args));
        }
    }
}

// 2. 中间件系统
class MiddlewareSystem {
    #middlewares = [];
    
    use(middleware) {
        this.#middlewares.push(middleware);
        return this;
    }
    
    async execute(context) {
        const runner = this.#middlewares.reduceRight(
            (next, middleware) => async () => {
                await middleware(context, next);
            },
            async () => {}
        );
        
        await runner();
    }
}