2023前端面试题总结:手写代码篇完整版

551 阅读7分钟

JavaScript知识手写题

实现一个自己的new操作符

new 操作符用于创建一个实例对象,它执行了以下步骤:

  1. 创建一个新的空对象:new 操作符首先会创建一个新的空对象。
  2. 设置对象的原型链接:新创建的对象的 [[Prototype]](隐式原型)被设置为构造函数的 prototype 属性。
  3. 将构造函数的上下文设置为新对象:在调用构造函数时,将 this 关键字绑定到新创建的对象,使构造函数内部的代码可以操作新对象。
  4. 执行构造函数的代码:构造函数内部的代码被执行,可能会在新对象上设置属性和方法。
  5. 如果构造函数没有返回对象,则返回新对象:如果构造函数没有显式返回一个对象,则 new 操作符会自动返回新创建的对象;如果构造函数返回一个非对象的值,则不会影响返回结果。

自己实现代码

//定义一个构造函数
function Person(name, age) {
    this.name = name
    this.age = age
}

Person.prototype.sayName = function () {
    console.log('My name is' + this.name)
}

function myNew(constructor, ...args) {
    // 创建一个新对象,使其__proto__指向构造函数的prototype
    const newObject = Object.create(constructor.prototype)

    // 执行构造函数,将属性或方法添加到创建的空对象上
    const result = constructor.apply(newObject, args)

    // 如果构造函数返回一个对象,则返回该对象,否则返回创建的新对象
    return (typeof result === 'object' && result !== null) ? result : newObject
}

const p1 = myNew(Person, 'Tom', 18)
console.log(p1)

打印结果
image.png

实现一个防抖函数

防抖函数可以帮助你限制高频率触发的事件,确保只有在一定时间间隔内没有新的触发时,才会执行特定的操作

// 创建一个防抖函数
function debounce(fn, delay) {
    // 定时器
    let timer = null
    // 返回一个函数,这个函数会在一个时间区间结束后的 delay 毫秒时执行 fn 函数
    return (...args) => {
        // 每次这个返回的函数被调用,就清除定时器,以保证不执行 fn
        clearTimeout(timer)
        // 当返回的函数被最后一次调用后(也就是用户停止了某个连续的操作),再过 delay 毫秒就执行 fn
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, delay)
    }
}

手写节流函数

在一些频繁触发的事件中,执行某个函数,会导致性能问题。节流函数可以帮助我们使频繁触发的事件时需要执行的函数,在指定时间间隔内只触发一次。

// 创建一个节流函数
function throttle(fn, delay) {
    // 记录上一次函数触发的时间
    var lastTime = 0
    return (...args) => {
        // 记录当前函数触发的时间
        var nowTime = Date.now()
        // 用当前时间减去上一次函数触发的时间,结果大于设置的时间间隔
        // 第一次会立即执行
        if (nowTime - lastTime > delay) {
            // 修正this指向问题
            fn.apply(this, args)
            // 同步时间
            lastTime = nowTime
        }
    }
}
// 处理函数
function handle(value1, value2) {
    console.log(value1, value2)
}

// 鼠标移动事件
window.addEventListener('mousemove', throttle(handle.bind(this,'abc', 123), 1000))

实现一个深拷贝,并解决循环引用问题?

深拷贝是在创建一个对象的副本时,递归地复制其所有嵌套属性和子对象。在深拷贝过程中,如果对象存在循环引用,即某个对象引用了自身或与其他对象形成了循环引用关系,那么简单的递归拷贝可能会导致无限循环,甚至造成内存溢出。为了解决循环引用问题,你可以在深拷贝过程中使用一些策略。以下是一种常见的方法:

  1. 使用一个缓存对象来跟踪已经被拷贝的对象,以及它们在新对象中的引用。这可以防止无限递归。
  2. 在每次拷贝一个对象之前,先检查缓存对象,如果该对象已经被拷贝,则直接返回缓存中的引用,而不是递归拷贝。
function deepCopyWithCycles(obj, cache = new WeakMap()) {
    if (obj === null || typeof obj !== 'object') {
        return obj;
    }

    if (cache.has(obj)) {
        return cache.get(obj);
    }

    if (obj instanceof Date) {
        return new Date(obj);
    }

    if (obj instanceof RegExp) {
        return new RegExp(obj);
    }

    const copy = Array.isArray(obj) ? [] : {};

    cache.set(obj, copy);

    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            copy[key] = deepCopyWithCycles(obj[key], cache);
        }
    }

    return copy;
}

const objA = {
    name: 'Object A'
};

const objB = {
    name: 'Object B'
};

objA.circularRef = objA;
objB.circularRef = objA;

const copiedObjA = deepCopyWithCycles(objA);

console.log(copiedObjA.name); // 输出: Object A
console.log(copiedObjA.circularRef.name); // 输出: Object A
console.log(copiedObjA.circularRef === copiedObjA); // 输出: true
console.log(copiedObjA.circularRef === copiedObjA.circularRef.circularRef); // 输出: true

在上面的示例中,deepCopyWithCycles 函数使用了一个 WeakMap 来缓存已经拷贝的对象,以及它们在新对象中的引用。这样,即使对象存在循环引用,也可以正确地处理。同时,这个函数也考虑了处理特殊类型如 Date 和 RegExp。

实现自己的call,apply,bind函数

  1. call 和 apply 是用于立即执行函数并传递参数的方法,其中 apply 接受参数的形式是数组。
  2. bind 是用于创建一个新函数,该函数会在稍后的调用中使用绑定的上下文。

实现call函数

Function.prototype.myCall = function(context, ...args) {
  context = context || window // 如果未传入上下文,则使用全局对象
  const uniqueKey = Symbol() // 使用一个唯一的键来避免覆盖原有属性

  context[uniqueKey] = this; // 将当前函数设置为上下文的属性
  const result = context[uniqueKey](...args) // 调用函数并传递参数

  delete context[uniqueKey] // 删除添加的属性
  return result // 返回函数执行的结果
}

function greet(name) {
  console.log(`Hello, ${name}! I am ${this.name}.`)
}

const person = { name: "Alice" }
greet.myCall(person, "Bob") // 输出:Hello, Bob! I am Alice.

实现apply函数

Function.prototype.myApply = function(context, args) {
  context = context || window;
  const uniqueKey = Symbol();

  context[uniqueKey] = this;
  const result = context[uniqueKey](...args);

  delete context[uniqueKey];
  return result;
};

function greet(name) {
  console.log(`Hello, ${name}! I am ${this.name}.`);
}

const person = { name: "Alice" };
greet.myApply(person, ["Bob"]); // 输出:Hello, Bob! I am Alice.

实现bind函数

Function.prototype.myBind = function(context, ...args1) {
  const originalFunction = this;
  return function(...args2) {
    context = context || window;
    const combinedArgs = args1.concat(args2); // 合并传入的参数
    return originalFunction.apply(context, combinedArgs);
  };
};

function greet(name) {
  console.log(`Hello, ${name}! I am ${this.name}.`);
}

const person = { name: "Alice" };
const boundGreet = greet.myBind(person);
boundGreet("Bob"); // 输出:Hello, Bob! I am Alice.

实现一个使数组乱序的函数

你可以使用 Fisher-Yates 洗牌算法来实现一个将数组乱序的函数。这个算法通过遍历数组,不断地交换当前元素与之前位置的随机元素来打乱数组的顺序。

function shuffleArray(array) {
    const shuffledArray = [...array]; // 创建一个数组的副本,以保持原始数组不受影响
    const n = shuffledArray.length;

    for (let i = n - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1)); // 生成一个随机索引
        [shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]]; // 交换元素
    }

    return shuffledArray;
}

const originalArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const shuffledArray = shuffleArray(originalArray);

console.log(shuffledArray); // 输出一个乱序的数组

在上面的示例中,shuffleArray 函数接受一个数组作为参数,并返回一个经过洗牌的新数组。该函数使用了 Fisher-Yates 洗牌算法,通过循环遍历数组,不断地将当前元素与随机位置的元素进行交换,从而打乱数组的顺序。

实现一个数组去重的方法

思路:创建一个空数组,循环原数组,依次将原数组元素push到新数组中,push之前判断新数组中是否包含当前元素,若包含则不用push

function uniqueArray(array) {
    const unique = [];
    
    for (const item of array) {
        if (!unique.includes(item)) {
            unique.push(item);
        }
    }
    
    return unique;
}

const originalArray = [1, 2, 2, 3, 4, 4, 5];
const uniqueArrayResult = uniqueArray(originalArray);

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

实现一个数组降维的方法

递归方法

function flattenArrayRecursive(arr) {
    let result = [];

    arr.forEach(item => {
        if (Array.isArray(item)) {
            result = result.concat(flattenArrayRecursive(item));
        } else {
            result.push(item);
        }
    });

    return result;
}

const nestedArray = [1, [2, [3, 4], 5], 6];
const flattenedArray = flattenArrayRecursive(nestedArray);

console.log(flattenedArray); // 输出: [1, 2, 3, 4, 5, 6]

迭代方法

function flattenArrayIterative(arr) {
    const stack = [...arr];
    const result = [];

    while (stack.length) {
        const next = stack.pop();

        if (Array.isArray(next)) {
            stack.push(...next);
        } else {
            result.unshift(next);
        }
    }

    return result;
}

const nestedArray = [1, [2, [3, 4], 5], 6];
const flattenedArray = flattenArrayIterative(nestedArray);

console.log(flattenedArray); // 输出: [1, 2, 3, 4, 5, 6]

实现数组的push,filter,map方法

实现自己的 push 方法

Array.prototype.myPush = function(...items) {
    const length = this.length;
    for (let i = 0; i < items.length; i++) {
        this[length + i] = items[i];
    }
    return this.length;
};

const arr = [1, 2, 3];
arr.myPush(4, 5);
console.log(arr); // 输出: [1, 2, 3, 4, 5]

实现自己的 filter 方法

Array.prototype.myFilter = function(callback) {
    const filteredArray = [];
    for (let i = 0; i < this.length; i++) {
        if (callback(this[i], i, this)) {
            filteredArray.push(this[i]);
        }
    }
    return filteredArray;
};

const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.myFilter(num => num % 2 === 0);
console.log(evenNumbers); // 输出: [2, 4]

实现自己的 map 方法

Array.prototype.myMap = function(callback) {
    const mappedArray = [];
    for (let i = 0; i < this.length; i++) {
        mappedArray.push(callback(this[i], i, this));
    }
    return mappedArray;
};

const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.myMap(num => num * num);
console.log(squaredNumbers); // 输出: [1, 4, 9, 16, 25]

实现‘观察者模式’和‘发布订阅模式’

详解"观察者"模式和"发布订阅"模式

实现一个eventEmitter方法

详解"观察者"模式和"发布订阅"模式

实现一个简单的redux

自己实现一个简单的Redux

实现个自己的Object.create函数

Object.create() 方法用于创建一个新对象,其中新对象的原型链被设置为指定的原型对象

function myCreate(proto) {
    if (proto === null || typeof proto !== 'object') {
        throw new TypeError('Object prototype may only be an Object or null');
    }

    function F() {}
    F.prototype = proto;

    return new F();
}

const personPrototype = {
    greet: function() {
        console.log(`Hello, my name is ${this.name}`);
    }
};

const person = myCreate(personPrototype);
person.name = 'Alice';
person.greet(); // 输出: Hello, my name is Alice

在上面的示例中,myCreate 函数模拟了 Object.create() 方法的行为。它接受一个原型对象作为参数,并创建一个新函数 F,将其原型设置为传入的原型对象。然后通过 new F() 创建一个新对象,使其原型链继承传入的原型对象。

实现一个自己的instanceof方法

instanceof 操作符用于检查一个对象是否是某个构造函数的实例

function myInstanceOf(obj, constructor) {
    if (typeof constructor !== 'function') {
        throw new TypeError('Right-hand side of instanceof is not callable');
    }

    let proto = Object.getPrototypeOf(obj);

    while (proto !== null) {
        if (proto === constructor.prototype) {
            return true;
        }
        proto = Object.getPrototypeOf(proto);
    }

    return false;
}

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

const person = new Person('Alice');

console.log(myInstanceOf(person, Person)); // 输出: true
console.log(myInstanceOf(person, Object)); // 输出: true
console.log(myInstanceOf(person, Array));  // 输出: false

在上面的示例中,myInstanceOf 函数模拟了 instanceof 操作符的行为。它接受一个对象和一个构造函数作为参数,然后通过递归地遍历对象的原型链,检查是否存在与构造函数的原型相等的原型。如果找到匹配的原型,就返回 true,否则返回 false。

实现一个自己的Promise函数

实现一个完整的 Promise 函数涉及到异步操作、状态管理(pending、fulfilled、rejected)、then 方法链式调用等等

function MyPromise(executor) {
    // 初始状态为 pending
    this.status = 'pending';
    // 用于存储 resolve 和 reject 时的值
    this.value = undefined;
    // 存储 then 方法中的回调函数
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
        if (this.status === 'pending') {
            this.status = 'fulfilled';
            this.value = value;
            this.onFulfilledCallbacks.forEach(callback => callback(this.value));
        }
    };

    const reject = (reason) => {
        if (this.status === 'pending') {
            this.status = 'rejected';
            this.value = reason;
            this.onRejectedCallbacks.forEach(callback => callback(this.value));
        }
    };

    try {
        executor(resolve, reject);
    } catch (error) {
        reject(error);
    }
}

MyPromise.prototype.then = function(onFulfilled, onRejected) {
    onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : value => value;
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason };

    if (this.status === 'fulfilled') {
        return new MyPromise((resolve, reject) => {
            setTimeout(() => {
                try {
                    const result = onFulfilled(this.value);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            }, 0);
        });
    }

    if (this.status === 'rejected') {
        return new MyPromise((resolve, reject) => {
            setTimeout(() => {
                try {
                    const result = onRejected(this.value);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            }, 0);
        });
    }

    if (this.status === 'pending') {
        return new MyPromise((resolve, reject) => {
            this.onFulfilledCallbacks.push((value) => {
                setTimeout(() => {
                    try {
                        const result = onFulfilled(value);
                        resolve(result);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            });

            this.onRejectedCallbacks.push((reason) => {
                setTimeout(() => {
                    try {
                        const result = onRejected(reason);
                        resolve(result);
                    } catch (error) {
                        reject(error);
                    }
                }, 0);
            });
        });
    }
};

// 示例使用
const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('Promise resolved!');
    }, 1000);
});

promise
    .then(value => {
        console.log(value); // 输出: Promise resolved!
        return value + ' And then...';
    })
    .then(value => {
        console.log(value); // 输出: Promise resolved! And then...
    });

实现一个自己的Promise.all

Promise.all() 是一个用于并行执行多个 Promise 对象,并在所有 Promise 都成功(resolved)时返回一个包含所有结果的 Promise

function myPromiseAll(promises) {
    return new Promise((resolve, reject) => {
        const results = [];
        let completedCount = 0;

        promises.forEach((promise, index) => {
            promise.then(
                result => {
                    results[index] = result;
                    completedCount++;

                    if (completedCount === promises.length) {
                        resolve(results);
                    }
                },
                reason => {
                    reject(reason);
                }
            );
        });
    });
}

// 示例使用
const promise1 = new Promise(resolve => setTimeout(() => resolve('Promise 1'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('Promise 2'), 500));
const promise3 = new Promise(resolve => setTimeout(() => resolve('Promise 3'), 800));

myPromiseAll([promise1, promise2, promise3])
    .then(results => {
        console.log(results); // 输出: ['Promise 1', 'Promise 2', 'Promise 3']
    })
    .catch(error => {
        console.error(error);
    });

myPromiseAll 函数接受一个 Promise 数组作为参数,并返回一个新的 Promise。它通过遍历每个 Promise 对象,在每个 Promise 成功时将结果存储在 results 数组中,当所有 Promise 都成功时,将 results 数组传递给新的 Promise 的 resolve 方法。

实现一个自己的Promise.race

Promise.race() 方法用于返回一个 Promise,它将在传入的多个 Promise 中有一个被 resolved 或 rejected 时,立即返回该 Promise 的状态和值

function myPromiseRace(promises) {
    return new Promise((resolve, reject) => {
        promises.forEach(promise => {
            promise.then(
                result => {
                    resolve(result);
                },
                reason => {
                    reject(reason);
                }
            );
        });
    });
}

// 示例使用
const promise1 = new Promise(resolve => setTimeout(() => resolve('Promise 1'), 1000));
const promise2 = new Promise(resolve => setTimeout(() => resolve('Promise 2'), 500));
const promise3 = new Promise((resolve, reject) => setTimeout(() => reject('Promise 3 Error'), 800));

myPromiseRace([promise1, promise2, promise3])
    .then(result => {
        console.log(result); // 输出: Promise 2
    })
    .catch(error => {
        console.error(error); // 不会执行,因为第一个 resolved 的 Promise 是 promise2
    });

myPromiseRace 函数接受一个 Promise 数组作为参数,并返回一个新的 Promise。它遍历每个 Promise 对象,当其中一个 Promise 被 resolved 或 rejected 时,即立即将状态和值传递给新的 Promise 的 resolve 或 reject 方法

实现一个完整的Ajax请求

实现一个完整的 AJAX 请求涉及创建 XMLHttpRequest 对象、设置请求参数、处理响应等多个步骤

function makeAjaxRequest(method, url, data, successCallback, errorCallback) {
    const xhr = new XMLHttpRequest();

    xhr.open(method, url, true);

    xhr.onreadystatechange = function() {
        if (xhr.readyState === XMLHttpRequest.DONE) {
            if (xhr.status === 200) {
                successCallback(xhr.responseText);
            } else {
                errorCallback(xhr.statusText);
            }
        }
    };

    xhr.setRequestHeader('Content-Type', 'application/json');
    xhr.setRequestHeader('Accept', 'application/json');

    if (method === 'GET') {
        xhr.send();
    } else {
        xhr.send(JSON.stringify(data));
    }
}

// 示例使用
const apiUrl = 'https://jsonplaceholder.typicode.com/posts/1';

makeAjaxRequest('GET', apiUrl, null,
    function(response) {
        const data = JSON.parse(response);
        console.log('Success:', data);
    },
    function(error) {
        console.error('Error:', error);
    }
);

makeAjaxRequest 函数封装了一个 AJAX 请求的基本流程。它接受请求的方法、URL、数据、成功回调函数和错误回调函数作为参数。内部创建了一个 XMLHttpRequest 对象,并设置了请求方法、URL、请求头等。在 onreadystatechange 事件中,检查请求状态和响应状态,根据情况调用相应的回调函数。

实现使用Promise封装Ajax请求

使用 Promise 封装 AJAX 请求可以让异步操作更加清晰和可读

function makeAjaxRequest(method, url, data) {
    return new Promise((resolve, reject) => {
        const xhr = new XMLHttpRequest();

        xhr.open(method, url, true);

        xhr.onreadystatechange = function() {
            if (xhr.readyState === XMLHttpRequest.DONE) {
                if (xhr.status === 200) {
                    resolve(xhr.responseText);
                } else {
                    reject(xhr.statusText);
                }
            }
        };

        xhr.setRequestHeader('Content-Type', 'application/json');
        xhr.setRequestHeader('Accept', 'application/json');

        if (method === 'GET') {
            xhr.send();
        } else {
            xhr.send(JSON.stringify(data));
        }
    });
}

// 示例使用
const apiUrl = 'https://jsonplaceholder.typicode.com/posts/1';

makeAjaxRequest('GET', apiUrl)
    .then(response => {
        const data = JSON.parse(response);
        console.log('Success:', data);
    })
    .catch(error => {
        console.error('Error:', error);
    });

makeAjaxRequest 函数返回一个 Promise 对象。在 Promise 的构造函数中,执行异步的 AJAX 请求操作,当请求成功时调用 resolve,当请求失败时调用 reject。

实现一个字符串翻转的方法

使用数组的 reverse 方法

function reverseString(str) {
    return str.split('').reverse().join('');
}

const originalStr = 'Hello, world!';
const reversedStr = reverseString(originalStr);
console.log(reversedStr); // 输出: "!dlrow ,olleH"

使用循环迭代

function reverseString(str) {
    let reversed = '';
    for (let i = str.length - 1; i >= 0; i--) {
        reversed += str[i];
    }
    return reversed;
}

const originalStr = 'Hello, world!';
const reversedStr = reverseString(originalStr);
console.log(reversedStr); // 输出: "!dlrow ,olleH"

使用递归

function reverseString(str) {
    if (str === '') {
        return '';
    }
    return reverseString(str.substr(1)) + str[0];
}

const originalStr = 'Hello, world!';
const reversedStr = reverseString(originalStr);
console.log(reversedStr); // 输出: "!dlrow ,olleH"

实现一个将数字每千分位用逗号隔开的方法(考虑有小数点)

你可以使用 JavaScript 提供的一些内置函数来实现将数字每千分位用逗号隔开的功能

function formatNumberWithCommas(number) {
    const parts = number.toString().split('.');
    parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return parts.join('.');
}

const number1 = 1234567;
const formattedNumber1 = formatNumberWithCommas(number1);
console.log(formattedNumber1); // 输出: "1,234,567"

const number2 = 1234567.89;
const formattedNumber2 = formatNumberWithCommas(number2);
console.log(formattedNumber2); // 输出: "1,234,567.89"

实现函数柯里化add(1)(2)(3)

function add(x) {
    return function(y) {
        if (typeof y === 'undefined') {
            return x;
        }
        return add(x + y);
    };
}

console.log(add(1)(2)(3)); // 输出: 6

实现一个查找文章中出现频率最高的单词的方法

我们按照每个单词之间使用单个空格隔开的规则实现,并排除常用介词,处理标点符号

function findMostFrequentWord(article) {
    const stopWords = ["a", "an", "and", "the", "in", "on", "of", "for", "to", "with", "it", "this", "that"];
    const words = article.toLowerCase().split(/\s+/);
    const wordCounts = {};

    words.forEach(word => {
        // 排除停用词和处理标点符号
        const cleanWord = word.replace(/[.,!?'"()]/g, '');
        if (cleanWord && !stopWords.includes(cleanWord)) {
            if (cleanWord in wordCounts) {
                wordCounts[cleanWord]++;
            } else {
                wordCounts[cleanWord] = 1;
            }
        }
    });

    let mostFrequentWord = '';
    let maxCount = 0;

    for (const word in wordCounts) {
        if (wordCounts[word] > maxCount) {
            mostFrequentWord = word;
            maxCount = wordCounts[word];
        }
    }

    return mostFrequentWord;
}

const articleText = "This is a sample text. It's a simple text for demonstration purposes. Simple text is good.";
const mostFrequent = findMostFrequentWord(articleText);
console.log("Most frequent word:", mostFrequent); // 输出: "text"

实现一个简单的双向绑定

使用Object.defineProperty

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>Document</title>
    </head>

    <body>
        <input id="inputElement" type="text">
        <div id="outputElement"></div>
    </body>

</html>
<script>
    let state = {}
    const inputElement = document.getElementById('inputElement')
    const outputElement = document.getElementById('outputElement')

    Object.defineProperty(state, 'value', {
        configurable: true,
        enumerable: true,
        get: () => {
            console.log('get value')
        },
        set: (newValue) => {
            console.log('set value: ', newValue)
            inputElement.value = newValue
            outputElement.innerHTML = newValue
        }
    })

    inputElement.addEventListener('keyup', (event) => {
        state.value = event.target.value
    })
</script>

使用proxy

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <input id="inputElement" type="text">
    <div id="outputElement"></div>
</body>

</html>
<script>
    let state = {}
    const inputElement = document.getElementById('inputElement')
    const outputElement = document.getElementById('outputElement')

    const handler = {
        get: (target, key) => {
            return target[key]
        },
        set: (target, key, value) => {
            target[key] = value
            inputElement.value = value
            outputElement.innerHTML = value
            return true
        }
    }

    const proxy = new Proxy(state, handler)

    inputElement.addEventListener('keyup', (event) => {
        proxy.value = event.target.value
    })
</script>

实现一个类的继承

class Animal {
    constructor(name) {
        this.name = name;
    }

    sayName() {
        console.log(`My name is ${this.name}`);
    }
}

class Dog extends Animal {
    constructor(name, breed) {
        super(name); // 调用基类构造函数以继承属性
        this.breed = breed;
    }

    bark() {
        console.log('Woof woof!');
    }
}

// 示例使用
const dog = new Dog('Buddy', 'Golden Retriever');
dog.sayName(); // 输出: "My name is Buddy"
dog.bark();    // 输出: "Woof woof!"

JavaScript算法手写题

2023前端面试题总结:算法篇完整版