【JavaScript + ES6】前端八股文面试题
JavaScript 、 ES6 部分
整理不易,家人们不想开通 VIP ,可以私我,有偿(2 yuan 购入PDF版)有更新都会踢。
【狗头保命,小的认真总结的,大部分都是我面试遇到的,感谢理解】
更新日志
2024年8月29日更新 —— ES6新特性有哪些?
2024年8月30日更新——xmlhttpRequest的解释
2024年8月31日更新——
- 防抖和节流的应用场景?
- 在开发过程中,原型链的应用场景?
- 箭头函数的作用
- 在JS中,怎么样实现面向对象的编程
文章目录
- JavaScript 、 ES6 部分
-
- 更新日志
-
- 1. `===`和`==`的区别
- 2. for 循环 var 定义和多个变量执行的次数
- 3.什么是闭包?
-
-
- 1)形成闭包的条件
- 2)示例解释
- 3)闭包的作用
- 4)注意事项
-
- 4.`async`返回的是什么类型?
- 5.箭头函数能不能`return`
- 6. `map()` `filter()` `reduce()` 返回值分别是什么?
-
-
- 1)`map()` 方法:创建一个新数组,其结果是对原数组中的每个元素调用提供的函数后的返回值。
- 2)`filter()` 方法:创建一个新数组,其中包含通过提供的函数实现的测试的所有元素。
- 3)`reduce()` 方法:对数组中的每个元素执行一个提供的 `reducer` 函数(升序执行),将其结果汇总为单个返回值。
-
- 7.阻止事件默认行为的方式有哪些?
-
-
- 1)在事件处理函数中返回 `false` :
- 2)使用 `preventDefault()` 方法:
- 3)对于表单提交事件,如果使用 `jQuery` 库,可以这样阻止:
-
- 8.设置事件时,最后参数`true`和`false`,冒泡和捕获的触发顺序是怎样的?
-
-
- 1)捕获阶段:
- 2)目标阶段:
- 3)冒泡阶段:
-
- 9.逻辑或 和 逻辑与
- 10.在 JavaScript 中,可以使用哪几种方法来判断数据类型是否相等?
-
-
- 1)`typeof` 操作符:可以返回一个表示数据类型的字符串。
- 2)`instanceof` 操作符:用于检测构造函数的 `prototype` 属性是否出现在某个实例对象的原型链上。
- 3)`Object.prototype.toString.call()` 方法:这是一种比较准确和全面的判断数据类型的方法。
-
- 11.对微任务宏任务的理解
-
-
- 1)宏任务
- 2)微任务
- 3)执行顺序示例
-
- 12.会造成js内存泄漏的是?
-
-
- 1)全局变量:
- 2)闭包:
- 3)定时器未及时清除:
- 4)事件监听未移除:
- 5)对 DOM 元素的引用未清除:
- 6)缓存未合理清理:
-
- 13.说说 var let const的区别
-
-
- 1)作用域
- 2)初始化
- 3)示例
- 4)总结
-
- 14.Promise 对象
-
-
- 1)**Promise** :
- 2)Promise 对象有三种状态:
-
- 15.js 继承的多种实现方式
-
-
- 1)原型链继承:
- 2)借用构造函数继承(经典继承):
- 3)组合继承(原型链 + 借用构造函数):
- 4) 原型式继承:
- 5)寄生式继承:
- 6)寄生组合式继承:
-
- 16.28.Date 对象
-
-
- 1)不传递参数,创建一个表示当前日期和时间的 Date 对象:
- 2)传递一个表示日期时间的字符串:
- 3)传递年、月、日、时、分、秒等参数:
- 4)Date 对象提供了许多方法来获取和操作日期时间的各个部分,例如:
-
- 17.空数组的 valueof 和 toString 值
- 18.js阻止冒泡的方法是?
-
-
- 1)使用 event.stopPropagation() 方法:
- 2)在 IE 浏览器中(某些旧版本),可以使用 event.cancelBubble = true :
-
- 19.阻止表单自动提交的方法:
-
-
- 1)在表单的提交按钮上,如果是 ` type="submit" `,可以将其修改为 ` type="button" ` ,这样点击按钮时就不会自动提交表单。
- 2)在表单的提交事件处理函数中,如果条件不满足,使用 `event.preventDefault()` 方法来阻止默认行为,即表单的自动提交。
-
- 20.js array不同方法的返回值?
- 21.在 JavaScript 中,一些常见的全局函数
- 22. 什么是深拷贝?什么是浅拷贝?
-
-
- 1)浅拷贝(Shallow Copy)
- 2)深拷贝(Deep Copy)
-
- 23.深拷贝和浅拷贝在实际开发中的应用场景?
-
-
- 1)浅拷贝的应用场景
- 2)深拷贝的应用场景
-
- 24.对Json.parse() 和Json.stringify()的理解
- 25.promise是同步还是异步的?Then方法呢?
-
-
- 1)promise本身是同步的
- 2)Then异步
-
- 26.前端中的事件流:
-
-
- 1)捕获阶段(Event Capture):
- 2)目标阶段(Event at Target):
- 3)冒泡阶段(Event Bubble):
-
- 27.在js中,如何去判断某个变量是什么类型的?
-
-
- 1)typeof 操作符
- 2)instanceof 运算符
- 3)Object.prototype.toString.call()
- 4)使用 constructor 属性
- 5)jQuery 的 $.type()
-
- 28.在js中,数组排序如何实现 (具体到代码逻辑,不能只说函数方法)?
-
-
- 1)sort() 方法:会改变原数组,并返回一个排序后的数组。
- 2)数字排序
- 3)自定义排序
- 4)逆序排序
-
- 29.在js中,去重如何实现,具体到逻辑实现:
-
-
- 1)使用 Set
- 2)使用 filter 和 indexOf
- 3) 使用 reduce
- 4) 使用对象的属性
- 5)使用 Map
-
- 30.在js中,map()和forEach()的区别:
-
-
- 1)返回值
- 2) 用途
- 3)链式调用
- 4)性能方面
-
- 31.数组很大的时候,快速查找某一目标项,如何解决这个问题:
-
-
- 1)使用哈希表
- 2)二分查找(适用于有序数组)
- 3)使用线性查找
- 4) 使用 findIndex 方法
-
- 31.ES6新特性有哪些?
-
-
- 1)let 和 const 声明
- 2)模板字符串
- 3)箭头函数
- 4)解构赋值
- 5)默认参数值
- 6)展开运算符(Spread Operator)
- 7)剩余参数(Rest Parameters)
- 8)Promise
- 9)Class(类)
- 10)模块(Module)
-
- 32.xmlhttpRequest的解释
- 33.防抖和节流的应用场景?
-
-
- 1)防抖的应用场景
- 2)节流的应用场景
-
- 34. 在开发过程中,原型链的应用场景?
-
-
- 1)继承
- 2)方法共享
- 3)对象的动态扩展
-
- 35.箭头函数的作用
-
-
- 1)简洁的语法
- 2)词法作用域和`this`的绑定
- 3)作为回调函数
-
1. ===
和==
的区别
在 JavaScript
中, ==
和 ===
都是用于比较操作的运算符。
但它们在比较规则上有明显的区别:
==
(相等运算符):在进行比较时会进行类型转换,然后比较值是否相等。
例如: ‘5’ == 5 会返回 true ,因为会将字符串 ‘5’ 转换为数字 5 进行比较。
===
(严格相等运算符):不仅比较值,还比较类型。只有值和类型都相同时,才返回 true 。
例如: ‘5’ === 5 会返回 false ,因为类型不同,一个是字符串,一个是数字。
[]===[] //false
{
}==={
} //false
null ===null // true
{
}=={
} // false
以下是一些 JavaScript 中关于比较判断的经典例题:
例题 1:
let num1 = 5;
let num2 = '5';
console.log(num1 == num2); //true
console.log(num1 === num2); //false
此题主要考察 == 和 === 在面对不同数据类型时的比较结果。
例题 2:
let obj1 = {
name: 'John' };
let obj2 = {
name: 'John' };
console.log(obj1 == obj2); //false
console.log(obj1 === obj2); //false
此例考查对象的比较,由于对象是引用类型,即使属性相同,两个不同的对象引用也不会相等。
例题 3:
let arr1 = [1, 2, 3];
let arr2 = [1, 2, 3];
console.log(arr1 == arr2); //false
console.log(arr1 === arr2); //false
此例针对数组的比较,与对象类似,即使元素相同,不同的数组引用也不相等。
例题 4:
let num = null;
console.log(num == undefined); //true
console.log(num === undefined); //false
此例涉及 null 和 undefined 的比较。
例题 5:
let str1 = 'hello';
let str2 = new String('hello');
console.log(str1 == str2); //true
console.log(str1 === str2); //false
此例考察字符串直接量和通过 String 构造函数创建的字符串对象的比较。
2. for 循环 var 定义和多个变量执行的次数
- 在
for
循环中使用var
定义变量时,会存在变量提升的问题,即变量会在函数作用域的顶部声明。 - 多个变量的执行次数取决于循环的条件。
例如,以下代码中:
for (var i = 0; i < 10; i++) {
for (var j = 0; j < 6; j++) {
// 循环体中的代码
}
}
外层循环会执行 10 次,内层循环会在外层循环的每一次迭代中执行 6 次。因此,总的执行次数为 10 * 6 = 60 次。
【注意】由于
var
定义的变量在整个函数作用域内都是可见的,可能会导致一些意外的结果。
在ES6
中,推荐使用let
或const
来定义变量,它们具有块级作用域,可以避免这些问题。
3.什么是闭包?
在 JavaScript
中,闭包(Closure
)是指有权访问另一个函数作用域中的变量的函数。
1)形成闭包的条件
- 存在一个内层函数。
- 内层函数引用了外层函数的变量。
- 外层函数将内层函数作为返回值或者传递给其他地方进行调用。
2)示例解释
以下是一个简单的闭包示例:
function outerFunction() {
const outerVariable = "I am from outer function";
function innerFunction() {
console.log(outerVariable);
}
return innerFunction;
}
const closureFunction = outerFunction();
closureFunction(); // 输出:I am from outer function
在这个例子中:
outerFunction
是外层函数,它定义了一个变量outerVariable
。innerFunction
是内层函数,它引用了outerVariable
。outerFunction
返回了innerFunction
,当把这个返回值赋给closureFunction
并调用closureFunction
时,innerFunction
仍然能够访问到outerVariable
,这就形成了闭包。
3)闭包的作用
- 数据封装和隐藏:可以创建私有变量,避免全局命名空间的污染。例如:
function createCounter() {
let count = 0;
return {
increment() {
count++;
return count;
},
decrement() {
count--;
return count;
},
};
}
const counter = createCounter();
console.log(counter.increment()); // 1
console.log(counter.increment()); // 2
在这个例子中,count
变量只能通过increment
和decrement
方法访问,外部无法直接修改count
,实现了数据的封装和隐藏。
- 模拟私有方法:在面向对象编程中,可以使用闭包来模拟私有方法。例如:
const myObject = (function () { let privateVariable = "private value"; function privateMethod() { console.log(privateVariable); } return { publicMethod() { privateMethod(); }, }; })(); myObject.publicMethod(); // 输出:private value
privateVariable
和privateMethod
只能在创建myObject
的立即执行函数内部访问,外部无法直接访问,模拟了私有变量和私有方法。
- 函数记忆化:闭包可以用于缓存函数的结果,避免重复计算。例如:
function memoizedAddTo80() { let cache = { }; return function (n) { if (n in cache) { return cache[n]; } else { console.log("long time"); cache[n] = n + 80; return cache[n]; } }; } const memoized = memoizedAddTo80(); console.log(memoized(5)); // long time,输出:85 console.log(memoized(5)); // 输出:85(直接从缓存中获取结果)
在这个例子中,闭包保存了cache
对象,用于存储已经计算过的结果,下次调用相同的参数时可以直接从缓存中获取结果,提高了函数的性能。
4)注意事项
- 闭包可能会导致内存泄漏:如果闭包引用了一个不再需要的变量,而这个变量又没有被正确地释放,就可能会导致内存泄漏。因此,在使用闭包时,要确保不再需要的变量能够被正确地垃圾回收。
- 闭包可能会影响性能:由于闭包会保留对外部变量的引用,这可能会导致一些性能问题,特别是在处理大量闭包或复杂的闭包结构时。因此,在使用闭包时,要注意性能优化,避免不必要的闭包使用。
以下是一个示例代码,用于给大家判断哪一个是闭包:
function outer() {
var outerVar = '外层变量';
function inner() {
console.log(outerVar);
}
return inner;
}
var closure = outer();
closure();
在上述代码中, inner
函数能够访问外部函数 outer
中的 outerVar
变量,因此 inner
函数是一个闭包。
4.async
返回的是什么类型?
在 JavaScript
中, async
函数总是返回一个 Promise
对象。
- 如果
async
函数内部的执行逻辑通过return
语句返回了一个值,那么这个Promise
对象最终会被解析为这个返回的值; - 如果函数内部抛出了异常或者发生了错误,那么这个
Promise
对象最终会被拒绝,并携带抛出的错误信息。
例如:
async function myAsyncFunction() {
return 5;
}
myAsyncFunction().then(result => console.log(result));
// 输出 5
在这个例子中, myAsyncFunction
函数返回的 Promise
对象最终被解析为数字 5 。
5.箭头函数能不能return
箭头函数可以返回一个值。
- 如果函数体只有一条表达式,可以省略
{}
和return
关键字,表达式的值会被自动返回。 - 如果函数体包含多条语句或需要显式返回一个值,则需要使用
{}
括起来,并使用return
关键字。
例如:
const sum = (a, b) => a + b; // 自动返回表达式的值
const multiply = (a, b) => {
return a * b; // 显式使用 return 返回值
};
6. map()
filter()
reduce()
返回值分别是什么?
1)map()
方法:创建一个新数组,其结果是对原数组中的每个元素调用提供的函数后的返回值。
const numbers = [1, 2, 3];
const doubled = numbers.map(num => num * 2);
// doubled 的结果为 [2, 4, 6]
2)filter()
方法:创建一个新数组,其中包含通过提供的函数实现的测试的所有元素。
const numbers = [1, 2, 3, 4, 5];
const evenNumbers = numbers.filter(num => num % 2 === 0);
// evenNumbers 的结果为 [2, 4]
3)reduce()
方法:对数组中的每个元素执行一个提供的 reducer
函数(升序执行),将其结果汇总为单个返回值。
const numbers = [1, 2, 3, 4, 5];
const sum = numbers.reduce((accumulator, currentValue) => accumulator + currentValue, 0);
// sum 的结果为 15
在这些方法中, reduce()
的返回结果通常与 map()
和 filter()
有所不同,因为它最终返回的是一个汇总的值,而不是一个新的数组。
7.阻止事件默认行为的方式有哪些?
1)在事件处理函数中返回 false
:
<button onclick="handleClick(); return false;">点击我</button>
<script>
function handleClick() {
// 事件处理逻辑
}
</script>
2)使用 preventDefault()
方法:
<button id="myButton">点击我</button>
<script>
document.getElementById('myButton').addEventListener('click', function(event) {
event.preventDefault();
// 事件处理逻辑
});
</script>
3)对于表单提交事件,如果使用 jQuery
库,可以这样阻止:
<form id="myForm">
<!-- 表单元素 -->
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<script>
$('#myForm').submit(function(event) {
event.preventDefault();
// 表单处理逻辑
});
</script>
8.设置事件时,最后参数true
和false
,冒泡和捕获的触发顺序是怎样的?
在设置事件处理程序时, true
表示使用捕获阶段, false
(默认值)表示使用冒泡阶段。
事件传播的顺序如下:
1)捕获阶段:
从最外层的祖先元素开始,向目标元素(触发事件的元素)传播。
2)目标阶段:
到达实际触发事件的目标元素。
3)冒泡阶段:
从目标元素开始,向其祖先元素传播。
如果将最后一个参数设置为
true
(捕获阶段),事件会先从最外层的祖先元素触发,然后依次向内传播,直到到达目标元素。
如果将最后一个参数设置为
false
(冒泡阶段),事件会先在目标元素触发,然后依次向其祖先元素传播。
9.逻辑或 和 逻辑与
- “逻辑或”
||
:- 当两个操作数中至少有一个为真(即非零、非空、非
false
等)时,整个表达式为真。 - 只有当两个操作数都为假时,表达式才为假。
- 当两个操作数中至少有一个为真(即非零、非空、非
例如:
true || false
的结果为true
,false || false
的结果为false
。
- “逻辑与”
&&
:- 只有当两个操作数都为真时,整个表达式才为真。
- 如果其中至少有一个为假,表达式就为假。
例如:
true && true
的结果为true
,true && false
的结果为false
。
10.在 JavaScript 中,可以使用哪几种方法来判断数据类型是否相等?
1)typeof
操作符:可以返回一个表示数据类型的字符串。
但对于某些类型(如 null
和 object
类型的数组、对象)的判断不够精确。
2)instanceof
操作符:用于检测构造函数的 prototype
属性是否出现在某个实例对象的原型链上。
但对于基本数据类型(如 Number
、 String
、 Boolean
等)不适用。
3)Object.prototype.toString.call()
方法:这是一种比较准确和全面的判断数据类型的方法。
它会返回一个形如 [object Type]
的字符串,其中 Type
表示具体的数据类型。
例如:
console.log(Object.prototype.toString.call(5)); // "[object Number]"
console.log(Object.prototype.toString.call('hello')); // "[object String]"
console.log(Object.prototype.toString.call(true)); // "[object Boolean]"
console.log(Object.prototype.toString.call(null)); // "[object Null]"
console.log(Object.prototype.toString.call({
})); // "[object Object]"
console.log(Object.prototype.toString.