前端开发工程师(主业)、技术博主(副业)、已过CET6
阿珊和她的猫_CSDN个人主页
牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》
蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入门到实战全面掌握 uni-app》
ES6(ECMAScript 2015)中引入了模块化系统,通过使用import
和export
关键字,可以使代码更加模块化、易维护。
import
关键字:用于导入其他模块中的变量、函数或类。导入语句放在模块的开头,如下所示:import { variable, functionName } from './module';
其中,variable
和functionName
是模块中定义的变量和函数,.
用于指定模块路径。
export
关键字:用于将模块中的变量、函数或类导出,以便在其他模块中导入。导出语句放在模块的末尾,如下所示:// 模块A
export function variableA() {
// ...
}
// 模块B
export function variableB() {
// ...
}
import()
函数可以实现动态导入,该函数接受一个模块路径作为参数,并在执行时返回该模块的导出对象。例如:const module = await import('./module');
const variable = module.variable;
import()
函数可以实现按需导入,该函数接受一个对象作为参数,对象中键为要导入的变量或函数,值为一个函数,该函数在导入时执行。例如:import('./module').then(module => {
const variableA = module.variableA;
const variableB = module.variableB;
});
import()
函数的try
和catch
语句,在导入失败时取消导入。例如:try {
import('./module1');
import('./module2');
} catch (error) {
console.error('循环导入错误:', error);
}
总之,ES6的模块化系统通过import
和export
关键字,使得代码更加模块化、易维护,提高了开发效率。
在ES6中,可以使用for...of
循环和for...in
循环来处理迭代器和迭代对象。
for...of
循环:用于遍历可迭代对象(如数组、字符串、Set、Map等),如:const arr = [1, 2, 3];
for (const value of arr) {
console.log(value); // 输出:1、2、3
}
for...in
循环:用于遍历对象的属性,如:const obj = { a: 1, b: 2, c: 3 };
for (const key in obj) {
console.log(key + ': ' + obj[key]); // 输出:a: 1、b: 2、c: 3
}
需要注意的是,for...of
循环只能用于可迭代对象,而for...in
循环可以用于普通对象和可迭代对象。
另外,for...of
循环可以与entries()
方法结合使用,以同时遍历键和值,如:
const obj = { a: 1, b: 2, c: 3 };
for (const [key, value] of Object.entries(obj)) {
console.log(key + ': ' + value); // 输出:a: 1、b: 2、c: 3
}
for...in
循环也可以与entries()
方法结合使用,但需要使用Object.keys()
或Object.values()
方法来获取对象的键或值,如:
const obj = { a: 1, b: 2, c: 3 };
for (const key of Object.keys(obj)) {
console.log(key + ': ' + obj[key]); // 输出:a: 1、b: 2、c: 3
}
for (const value of Object.values(obj)) {
console.log(value); // 输出:1、2、3
}
代理对象(Proxy)和反射对象(Reflect)是ES6中引入的两个新概念,它们的作用是提供对对象属性和方法的操作。
例如,可以使用代理对象实现对某个对象的属性进行访问控制:
const target = {
name: 'John',
age: 30
};
const proxy = new Proxy(target, {
get: function (target, key) {
console.log('Accessing:', key);
return target[key];
},
set: function (target, key, value) {
console.log('Updating:', key, value);
target[key] = value;
}
});
console.log(proxy.name); // 输出:Accessing: name
console.log(proxy.age); // 输出:Accessing: age
proxy.name = 'Jane'; // 输出:Updating: name Jane
console.log(target.name); // 输出:Jane
例如,可以使用反射对象获取对象的属性:
const obj = {
name: 'John',
age: 30
};
const name = Reflect.get(obj, 'name');
console.log(name); // 输出:John
或者使用反射对象设置对象的属性:
const obj = {
name: 'John'
};
Reflect.set(obj, 'age', 30);
console.log(obj); // 输出:{ name: 'John', age: 30 }
总之,代理对象和反射对象是ES6中提供的新功能,它们可以用于对对象属性和方法进行操作,实现数据验证、访问控制、日志记录等功能。
尾调用优化(Tail Call Optimization,TCO)是ES6中引入的一项优化技术,主要用于优化递归函数的性能。在函数调用过程中,如果一个函数在其内部调用另一个函数,而这个函数又返回了其自身的值,那么这个调用被称为尾调用。尾调用优化可以确保在尾调用的情况下,不会导致栈溢出,从而提高函数的执行效率。
ES6中通过引入Function.prototype.bind()
方法,实现了尾调用优化。bind()
方法可以创建一个新的函数,该函数在调用时会自动绑定原函数的this
值,并保留原函数的参数列表和返回值。通过使用bind()
方法,可以将原函数的调用链进行优化,从而实现尾调用优化。
例如,下面是一个使用bind()
方法实现尾调用优化的示例:
function factorial(n, acc = 1) {
if (n === 0) {
return acc;
}
return factorial.apply(null, [n - 1, n * acc]);
}
// 使用bind()方法优化尾调用
const factorialWithTCO = factorial.bind(null, 5);
factorialWithTCO(); // 输出:120
在这个示例中,factorial()
函数是一个递归函数,它在计算阶乘时会调用自身。通过使用apply()
方法调用factorial()
函数,可以实现尾调用优化。但是,这种优化方法可能会导致内存泄漏,因为apply()
方法会保留原函数的调用链。
为了解决这个问题,ES6引入了Function.prototype.call()
和Function.prototype.apply()
方法,它们可以实现尾调用优化,并避免内存泄漏。这些方法不会保留原函数的调用链,而是直接将参数传递给原函数并返回结果。
例如,下面是一个使用call()
方法实现尾调用优化的示例:
function factorial(n, acc = 1) {
if (n === 0) {
return acc;
}
return factorial(n - 1, n * acc);
}
// 使用call()方法实现尾调用优化
const factorialWithTCO = factorial.bind(null, 5).call();
console.log(factorialWithTCO); // 输出:120
在这个示例中,call()
方法将factorial.bind(null, 5)
返回的函数作为原函数,并直接将参数[]
传递给原函数,从而实现了尾调用优化。同时,call()
方法不会保留原函数的调用链,避免了内存泄漏的问题。