2023-12-28 17:21已编辑门头沟学院 计算机类
关注
快手前端一面
50min
大部分问的基础
很多手写题
1 手写一个new()
实现一个简单的 new() 函数的过程是创建一个对象并将其与指定的构造函数连接起来,具体步骤如下:
- 创建一个新的空对象。
- 将这个新对象的
__proto__属性链接到构造函数的原型对象(即构造函数的prototype属性)。 - 将构造函数的
this绑定到新创建的对象。 - 执行构造函数,并将参数传递给构造函数。
- 如果构造函数返回一个对象,则返回该对象;否则,返回新创建的对象。
以下是一个简单的实现:
function myNew(constructor, ...args) {
// 创建一个新的空对象
let obj = {};
// 将新对象的 __proto__ 属性链接到构造函数的原型对象
obj.__proto__ = constructor.prototype;
// 执行构造函数,并将 this 绑定到新对象
let result = constructor.apply(obj, args);
// 如果构造函数返回一个对象,则返回该对象;否则,返回新创建的对象
return result instanceof Object ? result : obj;
}
使用这个 myNew() 函数可以像使用 new 关键字一样来创建对象,例如:
function Person(name, age) {
this.name = name;
this.age = age;
}
let person = myNew(Person, 'John', 30);
console.log(person); // 输出 { name: 'John', age: 30 }
这样就实现了一个简单的 new() 函数。值得注意的是,这个实现并未考虑到 ES6 中的类、Symbol、Proxy 等特性,仅适用于普通的构造函数。
2 原型链 Object.create(null) {} 区别 结合题目说原型指向
原型链是 JavaScript 中一种对象之间的关系,通过原型链,一个对象可以从另一个对象继承属性和方法。在 JavaScript 中,对象可以通过 __proto__ 属性来访问其原型,通过原型链向上查找属性和方法。
现在来解释 Object.create(null) 和 {} 的区别以及与原型链的关系:
-
Object.create(null):
Object.create(null)创建了一个全新的对象,并将其原型设置为null。这意味着这个对象没有原型链,不会继承任何属性或方法,也不具备任何原生方法(如toString()、hasOwnProperty()等)。- 这种方式创建的对象通常被称为“纯净对象”或“字典对象”,它们非常适合用作存储键值对而不需要继承任何属性或方法的情况。
-
{}(空对象字面量):
{}是 JavaScript 中创建对象的常用方式之一,它会创建一个空对象,并将其原型链接到Object.prototype上。因此,这个对象会继承Object.prototype上的属性和方法,如toString()、hasOwnProperty()等。- 这种方式创建的对象属于一般的 JavaScript 对象,会继承一些原生方法和属性。
-
原型指向:
- 对象的原型通过
__proto__属性指向其原型对象,可以通过原型链向上查找属性和方法。 - 对于
{}创建的对象,默认情况下其原型链会指向Object.prototype,因此可以继承Object.prototype上的方法。 - 而对于
Object.create(null)创建的对象,其原型链上没有任何对象,因此不会继承任何属性或方法。
- 对象的原型通过
综上所述,Object.create(null) 创建的对象是一个纯净的、没有原型链的对象,而 {} 创建的对象会继承 Object.prototype 上的属性和方法。这两者在原型链和继承上存在明显的区别。
3 说说this指向
在 JavaScript 中,this 是一个关键字,用于指向当前执行上下文中的对象。this 的指向在不同的情况下会有所不同,主要取决于函数的调用方式。下面是 this 的几种常见指向情况:
-
全局作用域中的
this:- 在全局作用域中,
this指向全局对象(浏览器环境中为window,Node.js 环境中为global)。 - 例如:
console.log(this); // 输出 window(浏览器环境)
- 在全局作用域中,
-
函数中的
this:- 在普通函数中,
this的指向取决于函数的调用方式。如果函数是作为对象的方法被调用,this就指向该对象;否则,this指向全局对象(浏览器环境中)或undefined(严格模式下)。 - 例如:
function greet() { console.log(this.name); } const obj = { name: 'John', greet: greet }; obj.greet(); // 输出 John const func = obj.greet; func(); // 输出 undefined 或者报错(严格模式)
- 在普通函数中,
-
箭头函数中的
this:- 箭头函数的
this是词法作用域,即箭头函数的this继承自外部作用域的this,并且在定义时确定,不会被函数调用方式改变。 - 例如:
const obj = { name: 'John', greet: function() { const innerFunc = () => { console.log(this.name); }; innerFunc(); } }; obj.greet(); // 输出 John
- 箭头函数的
-
构造函数中的
this:- 在构造函数中,
this指向通过new关键字创建的新对象。 - 例如:
function Person(name) { this.name = name; } const person = new Person('Alice'); console.log(person.name); // 输出 Alice
- 在构造函数中,
-
DOM 事件处理函数中的
this:- 在 DOM 事件处理函数中,
this通常指向触发事件的 DOM 元素。 - 例如:
<button id="myButton">Click me</button> <script> document.getElementById('myButton').addEventListener('click', function() { console.log(this); // 输出点击的按钮元素 }); </script>
- 在 DOM 事件处理函数中,
总的来说,this 的指向取决于函数的调用方式以及函数的类型,在不同的情况下可能会指向不同的对象。理解 this 的指向是 JavaScript 开发中十分重要的一部分。
4 事件循环机制题目
5 nexttick题目 (面试官提示了差点答错了)
6 项目优化
7 手写防抖
8 手写两个有序数组的并集
下面是手写的两个有序数组的并集的 JavaScript 函数:
function mergeSortedArrays(arr1, arr2) {
let mergedArray = [];
let i = 0; // 用于遍历 arr1 的指针
let j = 0; // 用于遍历 arr2 的指针
// 遍历两个数组,将较小的元素依次添加到并集中
while (i < arr1.length && j < arr2.length) {
if (arr1[i] < arr2[j]) {
mergedArray.push(arr1[i]);
i++;
} else if (arr1[i] > arr2[j]) {
mergedArray.push(arr2[j]);
j++;
} else { // 如果两个元素相等,只添加一个到并集中
mergedArray.push(arr1[i]);
i++;
j++;
}
}
// 将剩余未遍历完的数组添加到并集中
while (i < arr1.length) {
mergedArray.push(arr1[i]);
i++;
}
while (j < arr2.length) {
mergedArray.push(arr2[j]);
j++;
}
return mergedArray;
}
// 示例
const arr1 = [1, 3, 5, 7, 9];
const arr2 = [2, 4, 6, 8, 10];
console.log(mergeSortedArrays(arr1, arr2)); // 输出 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
这个函数会遍历两个有序数组 arr1 和 arr2,并将它们合并成一个新的有序数组 mergedArray,最后返回这个新的数组作为两个数组的并集。
反问
技术栈和业务用的react和原生js,说不会卡vue,但是感觉有点寄
更新
早上11点面下午5点光速挂