JS高频手写题,看看你会多少

JS手写题

1. 手写 apply 方法

Function.prototype.myApply = function (thisArg, argsArray) {
    // 设置调用函数的上下文对象,如果没有传入上下文,则使用全局对象
    thisArg = thisArg || globalThis;
    
    // 创建一个唯一的 Symbol 以避免覆盖原有属性
    const fn = Symbol('fn');
    
    // 将当前函数绑定到传入的上下文对象上
    thisArg[fn] = this;

    // 如果没有传入参数,则默认为空数组
    argsArray = argsArray || [];

    // 调用函数并传入参数数组
    const result = thisArg[fn](...argsArray);

    // 删除临时绑定的函数
    delete thisArg[fn];

    // 返回函数执行结果
    return result;
};

// 示例代码
const food = {
    name: '西兰花炒蛋',
};

function func2(numA, numB, numC) {
    console.log(this);  // 打印函数的上下文对象
    console.log(numA, numB, numC);  // 打印传入的参数
    return numA + numB + numC;
}

const res2 = func2.myApply(food, [2, 4, 6]);
console.log('res2:', res2);  // 输出计算结果

2. 手写 call 方法

Function.prototype.myCall = function (thisArg, ...args) {
    // 设置调用函数的上下文对象
    thisArg = thisArg || globalThis;

    // 创建一个唯一的 Symbol 避免覆盖已有属性
    const fn = Symbol('fn');

    // 将函数绑定到上下文对象
    thisArg[fn] = this;

    // 传入参数调用函数
    const result = thisArg[fn](...args);

    // 删除临时绑定的函数
    delete thisArg[fn];

    // 返回函数执行结果
    return result;
};

// 示例代码
const food = {
    name: '西兰花炒蛋',
};

function func2(numA, numB, numC) {
    console.log(this);  // 打印上下文
    console.log(numA, numB, numC);  // 打印参数
    return numA + numB + numC;
}

const res2 = func2.myCall(food, 2, 4, 6);
console.log('res', res2);  // 输出结果

3. 手写 bind 方法

Function.prototype.myBind = function (thisArg, ...args) {
    // 保存当前函数
    const self = this;
    
    // 返回一个新函数
    return function boundFunction(...newArgs) {
        // 判断是否通过 new 调用了该函数
        const isNewOperatorUsed = this instanceof boundFunction;

        // 根据调用方式决定上下文
        const context = isNewOperatorUsed ? this : thisArg;

        // 使用 apply 调用原函数,合并参数
        return self.apply(context, [...args, ...newArgs]);
    };
};

// 示例代码
const person = {
    name: 'Tom',
};

function greet(greeting, punctuation) {
    console.log(`${greeting}, ${this.name}${punctuation}`);
}

const boundGreet = greet.myBind(person, 'Hello');
boundGreet('!');  // 输出 "Hello, Tom!"

4. 手写 AJAX 请求

function ajax(url, method, data = null) {
    const xhr = new XMLHttpRequest();  // 创建 XMLHttpRequest 对象
    xhr.open(method, url, true);  // 打开连接,true 表示异步

    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) {  // 请求完成
            if ((xhr.status >= 200 && xhr.status < 300) || xhr.status === 304) {
                alert(xhr.responseText);  // 请求成功,输出响应
            } else {
                console.log("Request was unsuccessful: " + xhr.status);  // 请求失败
            }
        }
    };

    if (method.toLowerCase() === 'post') {
        xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    }

    xhr.send(data);  // 发送请求
}

// 测试 GET 请求
ajax('https://jsonplaceholder.typicode.com/posts/1', 'GET');

5. 防抖(Debounce)

function debounce(func, wait) {
    let timeoutId;
    return function (...args) {
        if (timeoutId) {
            clearTimeout(timeoutId);  // 如果有定时器,先清除
        }
        timeoutId = setTimeout(() => {
            func(...args);  // 延迟执行函数
        }, wait);
    };
}

6. 节流(Throttle)

function throttle(func, wait = 0) {
    let timeId;
    return function (...args) {
        if (timeId !== undefined) {
            return;  // 如果有定时器在运行,则跳过调用
        }
        const _this = this;
        timeId = setTimeout(() => {
            func.apply(_this, args);  // 调用函数
            timeId = undefined;  // 重置定时器 ID
        }, wait);
    };
}

7. 数组扁平化

const arr = [1, [2, [3, [4]], 5]];

function flatten(arr) {
    let result = [];
    arr.forEach(item => {
        if (Array.isArray(item)) {
            result = result.concat(flatten(item));  // 递归处理数组
        } else {
            result.push(item);
        }
    });
    return result;
}

console.log(flatten(arr));  // 输出 [1, 2, 3, 4, 5]

8. 数组去重

let arr = [1, 2, 3, 2, 4, 5, 3, 6, 2];

function arrayToHeavy(arr) {
    let newArr = [];
    for (let i = 0; i < arr.length; i++) {
        if (newArr.indexOf(arr[i]) === -1) {
            newArr.push(arr[i]);  // 只添加未存在的元素
        }
    }
    return newArr;
}

console.log(arrayToHeavy(arr));  // 输出去重后的数组

9. 柯里化

function sumMaker(length) {
    let nums = [];

    function sum(...args) {
        nums.push(...args);
        if (nums.length >= length) {
            const res = nums.slice(0, length).reduce((p, v) => p + v, 0);  // 满足长度后计算总和
            nums = [];  // 重置数组
            return res;
        } else {
            return sum;  // 返回自身以便继续调用
        }
    }

    return sum;
}

const sum6 = sumMaker(6);
console.log(sum6(1, 2, 3)(4, 5, 6));  // 输出 21

10. 浅拷贝

const original = {
    name: 'John',
    age: 30,
    skills: ['javascript', 'vue'],
};

const copy = Object.assign({}, original);
copy.name = 'Alice';  // 修改副本不会影响原始对象
copy.skills.push('React');  // 数组是引用类型,副本和原对象共享引用

console.log(original);
console.log(copy);

11. 深拷贝

function deepClone(obj) {
    if (typeof obj !== 'object' || obj === null) {
        return obj;  // 基本类型直接返回
    }
    const result = Array.isArray(obj) ? [] : {};  // 根据类型创建新对象

    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            result[key] = deepClone(obj[key]);  // 递归拷贝子属性
        }
    }
    return result;
}

const obj1 = {
    name: 'Alice',
    age: 25,
    skills: ['JavaScript', 'Vue', 'React'],
    details: {
        hobbies: ['reading', 'coding'],
        location: {
            city: 'New York',
            country: 'USA',
        },
    },
};

const obj2 = deepClone(obj1);  // 深拷贝对象
obj2.name = 'Bob';
obj2.details.location.city = 'San Francisco';

console.log('Original:', obj1);  // 原始对象不受影响
console.log('Cloned:', obj2);

12. 手写 new

function myNew(constructor, ...args) {
    const obj = Object.create(constructor.prototype);  // 创建对象,链接到原型
    const result = constructor.apply(obj, args);  // 执行构造函数
    return typeof result === 'object' && result !== null ? result : obj;  // 返回新对象
}

function Person(name, age) {
    this.name = name;
    this.age = age;
}

Person.prototype.sayHello = function () {
    console.log(`Hello, my name is ${this.name}, I am ${this.age} years old.`);


};

const person1 = myNew(Person, 'John', 30);
person1.sayHello();  // 输出 "Hello, my name is John, I am 30 years old."

13.实现sleep

function sleep(func,delay){
    return new Promise((resolve,reject) =>{
        setTimeout(() => {
            resolve(func())
        },delay)
    })
}

function say(name){
    console.log(name)
}
async function go(){
    await sleep(() => say('张继科'),1000)
    await sleep(() => say('马龙'),2000)
}
go()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

前端第一深情

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值