面试题(ES6)

70 阅读7分钟

ES6考题

1. var、let、const三者区别
  1. 作用域

    var:
    	函数作用域(Function Scope):var声明的变量只在其所在的函数内有效,如果在函数外部声明,则为全局变量。
    
    letconst:
    	块作用域(Block Scope):letconst 声明的变量只在其所在的代码块(如 if 语句、循环等)内有效。
    
  2. 变量提升

    var 声明的变量会被提升到函数或全局作用域的顶部,但未初始化的变量在提升时为 undefinedletconst在声明之前不能访问(会导致 ReferenceError),这被称为暂时性死区。
    
  3. 重新赋值

    var:可以重新赋值。
    let:也可以重新赋值。
    const:不可重新赋值。声明时必须初始化,之后不能改变其绑定的值(但如果是对象,内部的属性是可以修改的)。
    
    const obj = {
    	a:1
    }
    obj.a = 2; //这里可以修改
    
2. js中什么是可选链操作符
可选链操作符(Optional Chaining Operator)是 JavaScript 中的一种语法,允许你安全地访问对象的深层嵌套属性,而不必显式检查每个级别的存在性。它的语法是 ?.,在访问对象属性时,如果前面的表达式为 nullundefined,则整个表达式的结果为 undefined,而不是抛出错误。

语法:

const list = [
	{
		id:'1',
		name:'张三',
		address:{
			province:'河北省',
			city:'张家口',
		}
	},
	{
		id:'2',
		name:'李四',
		address:{
			province:'山西省',
			city:'太原市',
		}

	},
	{id:'3',name:'王五'}
]

const newList = list.map(item=>{
	return item.address.city;//报错
})	

const newList = list.map(item=>{
	return item.address?.city;//返回:['张家口', '太原市', undefined]
})	
3. ES6新增数组方法有哪些

ES6(ECMAScript 2015)引入了一些新的数组方法,使得数组的操作更加方便和高效。以下是一些主要的新增数组方法:

  1. Array.from() 将类数组对象或可迭代对象转换为数组。
const arrayLike = { 0: 'a', 1: 'b', length: 2 };
const arr = Array.from(arrayLike); // ['a', 'b']
  1. Array.of() 创建一个新数组实例,使用可变数量的参数作为数组元素。
const arr = Array.of(1, 2, 3); // [1, 2, 3]
  1. Array.prototype.find() 返回数组中满足提供的测试函数的第一个元素,如果没有找到则返回 undefined。
const numbers = [1, 2, 3, 4, 5];
const found = numbers.find(num => num > 3); // 4
  1. Array.prototype.findIndex() 返回满足提供的测试函数的第一个元素的索引,如果没有找到则返回 -1。
const numbers = [1, 2, 3, 4, 5];
const index = numbers.findIndex(num => num > 3); // 3
  1. Array.prototype.fill() 用静态值填充数组的全部或部分元素。
const arr = new Array(5).fill(0); // [0, 0, 0, 0, 0]
  1. Array.prototype.copyWithin() 在数组内部复制指定位置的元素到另一个位置(可以重叠)。
const arr = [1, 2, 3, 4, 5];
arr.copyWithin(0, 3); // [4, 5, 3, 4, 5]
  1. Array.prototype.entries() 返回一个新的数组迭代器对象,该对象包含数组中每个索引的键/值对。
const arr = ['a', 'b', 'c'];
const iterator = arr.entries();

for (const [index, value] of iterator) {
    console.log(index, value);
}
// 0 'a'
// 1 'b'
// 2 'c'
  1. Array.prototype.keys() 返回一个新的数组迭代器对象,该对象包含数组中每个索引的键。
const arr = ['a', 'b', 'c'];
const iterator = arr.keys();

for (const key of iterator) {
    console.log(key);
}
// 0
// 1
// 2
  1. Array.prototype.values() 返回一个新的数组迭代器对象,该对象包含数组中每个索引的值。
const arr = ['a', 'b', 'c'];
const iterator = arr.values();

for (const value of iterator) {
    console.log(value);
}
// 'a'
// 'b'
// 'c'
  1. Array.prototype.includes() 判断数组是否包含某个值,返回 true 或 false。
const arr = [1, 2, 3];
console.log(arr.includes(2)); // true
console.log(arr.includes(4)); // false
4. 箭头和普通函数区别
  1. this绑定

    普通函数:this 的值由调用函数的上下文决定。调用时的上下文会影响 this 的值。this指向可以修改。

    箭头函数:this 的值由外层作用域决定,永远指向定义时的 this。this指向不能修改。

    var a = '外部';
    let obj = {
    	a:'内部',
    	run(){
    		// return ()=>{
    		// 	console.log( this.a )
    		// }
    		return function(){
    			console.log( this.a );
    		}
    	}
    }	
    
    obj.run()();
    
  2. 构造函数

    普通函数:可以用作构造函数,通过 new 关键字创建实例。
    箭头函数:不能用作构造函数,不能使用 new 关键字。
    
  3. arguments 对象

    普通函数:有 arguments 对象,可以访问调用函数时传入的所有参数。
    箭头函数:没有 arguments 对象。如果需要,可以使用剩余参数语法 ...rest。
    
  4. Generator 函数

    普通函数:可以使用yield命令,可以当作Generator 函数。
    箭头函数:不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
    
5. map和set区别
  1. 键/值的唯一性:

    Map:键是唯一的,但值可以重复。
    Set:值是唯一的,不能重复添加同样的值。
    
  2. 存储方式

    Set 使用类似于数组的方式存储值。 Map 使用键值对的方式存储数据。

总结:使用场景

Set 适用于需要存储一组唯一值,并且不关心顺序的场景,例如去重、判断元素是否存在等。
Map 适用于需要将值与特定键关联的场景,例如存储键值对的配置信息、构建字典、缓存等。
6. Promise考题
6.1 promise你是怎么理解的
面试回答:
Promise是一个异步编程解决方案,主要解决的就是没有Promise之前的回调函数的问题,因为回调函数可能会出现调用死亡地狱的问题,这样会让我们的代码不好阅读,不好维护,所以诞生Promise来解决此问题,另外Promise本身是对象,Promise.thencatch是属于微任务,而且每一个then都返回一个PromisePromise就是一个容器,Promise对象代表一个异步操作,其中包含三种状态,进行中、已成功、已失败,当然Promise也有缺点,比如每一个then都是一个单独的作用域,假设在某一个then中定义一个变量在其他then中是无法直接使用的。当然Promise还有更多的方法,比如all、race,在项目中如果多个请求,需要一起返回数据可以用all。
6.2 promise的链式调用是怎么实现的

Promise的链式调用是通过返回Promise对象来实现的。下面是Promise链式调用的基本原理和实现方式:

Promise的基本结构,一个Promise对象有三种状态:

Pending(进行中):初始状态,既不是成功,也不是失败。
Fulfilled(已成功):操作成功完成。
Rejected(已失败):操作失败。

链式调用的实现:链式调用的核心在于then方法。then方法返回一个新的Promise,这允许你在Promise完成后继续调用then方法。

下面是一个简化的Promise实现示例,展示了如何实现链式调用:

class MyPromise {
    constructor(executor) {
        this.state = 'pending';
        this.value = undefined;
        this.reason = undefined;
        this.onFulfilledCallbacks = [];
        this.onRejectedCallbacks = [];

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

        const reject = (reason) => {
            if (this.state === 'pending') {
                this.state = 'rejected';
                this.reason = reason;
                this.onRejectedCallbacks.forEach(fn => fn(reason));
            }
        };

        // 执行传入的 executor 函数
        executor(resolve, reject);
    }

    then(onFulfilled, onRejected) {
        return new MyPromise((resolve, reject) => {
            const handleFulfilled = () => {
                try {
                    const result = onFulfilled(this.value);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            };

            const handleRejected = () => {
                try {
                    const result = onRejected(this.reason);
                    resolve(result);
                } catch (error) {
                    reject(error);
                }
            };

            if (this.state === 'fulfilled') {
                handleFulfilled();
            } else if (this.state === 'rejected') {
                handleRejected();
            } else {
                this.onFulfilledCallbacks.push(handleFulfilled);
                this.onRejectedCallbacks.push(handleRejected);
            }
        });
    }
}


const promise = new MyPromise((resolve, reject) => {
    setTimeout(() => {
        resolve('Success!');
    }, 1000);
});

promise
    .then((result) => {
        console.log(result); // 输出 "Success!"
        return 'Next success!';
    })
    .then((result) => {
        console.log(result); // 输出 "Next success!"
    })
    .catch((error) => {
        console.error(error);
    });
6.3 promise错误捕获有几种方法

方式一:catch

let promise = new Promise((resolve, reject) => {
  throw new Error('An error occurred');
});
 
promise.catch((error) => {
  console.error('Error caught:', error);
});

方式二:try...catch

async function asyncFunction() {
  try {
    throw new Error('An error occurred');
  } catch (error) {
    console.error('Error caught:', error);
  }
}
 
asyncFunction();
6.4 promise的all和promise的race有什么区别
总结:
Promise.all: 等待所有 Promise 完成,只有在所有 Promise 成功时才会成功。
Promise.race: 返回第一个完成的 Promise,无论其成功或失败。
7. setTimeout、Promise、async/await的区别
一、宏任务、微任务
setTimeout是宏任务
Promise是一个对象,例如then是微任务
async/await是基于 Promise 的高级语法糖,也是微任务

二、使用场景
setTimeout 主要用于定时执行任务,适用于需要在特定时间点执行的操作。
Promise 用于封装异步操作的结果,提供了一种更灵活的方式来处理异步逻辑和错误处理。
async/await 提供了更简洁、更易于理解的异步编程方式,尤其适合处理复杂的异步流程。
8. es6平时用的比较多的有哪些?
letconst命令
变量的解构赋值
字符串的新增方法
箭头函数
数组的新增方法
对象的新增方法
运算符,比如?.
SetMap 数据结构
Promise 对象
包括vue3用到的Proxy
也了解过:Generator函数
当然async/await常用到
Class
Module 的语法