[面试题]ES6 Javascript
-
ES6 箭头函数和普通函数有什么区别?
1)定义方式:箭头函数使用箭头(=>)语法,省略了 function 关键字。
2)参数处理:如果只有一个参数,箭头函数可以省略括号。
3)函数体:如果函数体只有一条语句,箭头函数可以省略花括号和 return 关键字
4)箭头函数没有自己的 this 对象,而是从其作用域链的上一层继承 this。箭头函数中 this 的指向在它被定义的时候就已经确定了。
5)箭头函数的 this 指向不能通过 call、apply、bind 等方法改变
6)箭头函数不可以当作构造函数,不可以对箭头函数使用 new 命令
7)其他特性:箭头函数没有自己的 arguments对象,没有原型 prototype,不能用作 Generator 函数,不能使用 yeild 关键字,没有 super.
-
ES6 箭头函数能当构造函数吗?
不能。箭头函数没有自己的 this 对象,没有 argument、caller、prototype 属性,且无法通过 new 关键字调用。
-
ES6 有哪些新特性?
1)let和 const:具有块级作用域,let 用来声明变量可重新赋值,const 用来声明常量不可再次赋值。
2)箭头函数:新的函数声明方式,语法简洁。
3)模版字符串:字符串插值功能,可定义多行字符串。"hello,${name}"
4)解构赋值:是一种 JavaScript 表达式,它允许从数组或对象中提取属性或值,并将这些值赋给其他变量{a,b}={name:"a",age:11} [a,b]=[1,2]
5)默认参数:函数参数可设置默认值。(name="default")=>"hello,${name}"
6)扩展运算符:可以将数组展开为逗号分隔的参数序列,或者合并多个对象或数组。...
7)类与模块:通过 class 关键字定义类,使用 import 和 export 来导入和导出模块.
8)Promise:用于处理异步操作。
9)Symbol和迭代器:提供了一种新的原始数据类型和自定义迭代行为的方式,
10)新的数据结构:Map[key-value]、Set[去重]。
11)其他:对象属性简写,属性和方法简写,提升了JavaScript 的编码效率和可读性。
-
ES6 新增的 Symbol 基础数据类型有什么作用?
1)用作对象属性名:可以确保属性名称的唯一性。
2)防止属性冲突:可以避免在不同模块不同库之间发生属性命名冲突。
3)内置 Symbol:ES6 提供了一些内置的Symbol,如 symbol.iterator、symbol.match 等。
4)全局注册表:用 symbo1.for()方法创建的 Symbol会被放入一个全局注册表中。通过 symb1.keyFor()可以在注册表中检测值是否存在。
5)迭代器和生成器:Symbol可以用于自定义对象的迭代行为,如: symbo1.iterator 方法,可以使对象可迭代。
let mySymbol = Symbol('mySymbol');
let obj = {
[mySymbol]: 'value'
};
console.log(obj[mySymbol]); // 'value'
--------------------------------------------
let mySymbol = Symbol('hidden');
let obj = {
[mySymbol]: 'hiddenValue',
visible: 'visibleValue'
};
console.log(Object.keys(obj)); // ['visible']
console.log(Object.getOwnPropertySymbols(obj)); // [Symbol(hidden)]
在JavaScript中,对象属性名都是字符串类型。如果两个不同的对象使用相同的属性名,就会出现冲突,导致代码出现意想不到的问题。为了避免这种情况,ECMAScript6(ES6)引入了Symbol类型,用于表示独一无二的标识符。Symbol是一种原始数据类型,它的值是唯一的且不可变。
Symbol类型的特点
- 唯一性:每个Symbol值都是唯一的,无法通过简单的值比较相等。
- 不可变性:Symbol值一旦创建,就不能被修改。
- 属性标识符:Symbol类型的值可以作为对象属性的标识符(key)。
Symbol类型的常用场景和示例
- 创建唯一的对象属性
Symbol可以用作对象的属性键,以创建唯一的属性名,避免命名冲突。
const symbolKey = Symbol('myKey'); const obj = {}; obj[symbolKey] = 'value'; console.log(obj[symbolKey]); // 输出 'value'
- 防止属性名冲突
在开发第三方插件或框架时,使用Symbol可以避免因为添加了同名的属性或方法而覆盖掉框架中原有的属性或方法。
const firstName = Symbol("firstName"); const person = { [firstName]:"John", lastName:"Doe" }; console.log(person[firstName]); // 输出: "John"
- 创建私有属性
虽然Symbol不能实现真正的私有变量效果,但可以作为对象属性的键名,这些属性对于常规的对象遍历和操作是不可见的。
const _private = Symbol('private'); class MyClass { constructor() { this[_private] = 'private value'; } getPrivateValue() { return this[_private]; } } const instance = new MyClass(); console.log(instance.getPrivateValue()); // 输出 'private value' console.log(instance._private); // 输出 undefined
- 定义常量
使用Symbol可以定义一些常量,这些常量具有唯一性,不会被意外修改或覆盖。
const TYPE_OBJ = { TYPE1: Symbol(), TYPE2: Symbol() }; function checkType(obj) { switch(obj) { case TYPE_OBJ.TYPE1: console.log('type1'); break; case TYPE_OBJ.TYPE2: console.log('type2'); break; } } checkType(TYPE_OBJ.TYPE1); // 输出 'type1'
- 使用内置的Symbol常量
JavaScript中有一些内置的Symbol常量,例如
Symbol.iterator
、Symbol.toPrimitive
等,它们可以用来修改对象的默认行为。const myObj = { [Symbol.toPrimitive](hint) { if (hint === 'number') { return 42; } if (hint === 'string') { return 'forty-two'; } return 'default'; } }; console.log(myObj + 1); // 输出 43 console.log(String(myObj)); // 输出 'forty-two' console.log(Number(myObj)); // 输出 42
总结
Symbol是ES6中新增的一种基本数据类型,用于表示独一无二的标识符。它具有唯一性、不可变性和作为属性标识符的特性。通过使用Symbol,可以避免对象属性名的冲突,创建私有属性,定义常量以及实现各种标识符相关的功能。Symbol类型在许多库和框架中被广泛应用,是JavaScript中一个重要的数据类型。
-
ES Module 与 CommonJS模块方案有什么异同?
- 使用语法:
- ES import/export CommonJS
- CommonJS:module.exports|exports /requrie
- 加载机制
- ES Modules 在编译时加载,采用异步加载模块方式,支持动态导入(按需加载导入模块),会更适合在浏览器环境中使用。
- Commnons 在运行时加载,采用同步加载模块方式,所以不支持动态导入;同步加载是等模块加载完毕后才会执行代码。这种加载方式通常在服务端使用,因为服务端文件都在本地,不会引起明显的延迟问题,但不适合客户端(如浏览器),因为会导致浏览器在等待模块下载和解析期间暂停执行。
- 运行环境
- ES Modules 是 ES6 引入的官方标准化模块系统,支持异步加载,被现代浏览器广泛支持,Node.js 现在也支持 ES Modules,CommonJS 主要用于 Node.js 环境。
- 变量作用域
- ES Modules 的顶层 this 是 undefined,因为 ESM 模块在严格模式下执行,并且每个模块都有自己的顶层作用域,模块内部的变量默认不会被全局共享。
- Commons 每个文件都是其模块的顶层作用域,因为 CJS不会使用严格模式,它们的导入导出基于对象的引用,所以可以共享模块内部的变量,
- 使用场景
- ES Modules 更话合现代JavaScnpt开发,因为 ESM 是Javascnpt官方的模块系统,现代浏览器原生支持,支持静态分析、异步加载、严格模式等特性,有利于前端代码拆分,以懒加载方式优化加载性能。
- ES Modules 更适合需要利用静态分析来进行 Tree shaking(树摇优化)优化的项目:Tree shaking,是一种只打包必要模块代码的方法,依赖于 ESM 的静态结构可以移除未被使用的代码。
- CommonJS 更适合 Node.js 服务端开发,模块加载是同步的,方便变量共享。
- 混合场景:当需要在同一个项目中混合使用两种模块系统时,可以通过设置Webpack或其他模块打包工具来处理。
-
如果 new 一个箭头函数会怎么样?
会报错,因为箭头函数设计上并不具备构造函数的特性,没有自己的 this 对象,没有 prototype 属性,所以 new 一个箭头函数会报错。
-
ES6 箭头函数的 **this **指向哪里?
- ES6 箭头函数的 this 指向定义它时所处上下文的对象的 this。
- 箭头函数的 this 指向是固定的,在函数定义时就确定了,之后不会再改变
-
说说 ES6 扩展运算符的作用及使用场景?
1)数组操作:合并数组、复制数组、将数组作为参数传递给函数等。
2)函数参数:将不定数量的参数收集为一个数组,或者将数组解构为函数的参数。3)对象操作:合并对象、创建新的对象副本
4)字符串操作:将字符串转换为字符数组,方便遍历和操作每个字符。
-
ES6 的 Proxy 可以实现什么功能?
ES6 的 Proxy 是一个强大的工具,可以用来创建虚拟化的对身通过自定义基本操作(如属性查找、赋值、枚举、函数调用等)的行为来实现各种高级功能。主要功能包括:
1)拦截和定义对象的基本操作,比如属性访问、赋值、删除函数调用等。
2)实现自定义的行为,比如数据验证、属性保护、自动填默认值等。
3)实现观察者模式,可以轻松实现对象的监听和变化追踪,
4)创建虚拟属性和方法,使得代码更灵活和动态。
5)代理外部接口,可以将 API调用封装为本地对象的属性订问操作。
-
什么是 ES6 的数组解构和对象解构?
这些功能让我们能够直接从数组或对象中提取值并赋予变量,从而减少代码冗长度和提升可读性。数组解构允许你按顺序获取数组中的元素,而对象解构让你可以直接获取对象中的属性值。
-
ES6 中,如何提取深度嵌套的对象中的指定属性?
-
说说你对 ES6 中 rest 参数的理解?
rest参数是ES6 中新增的一项语法,用于表示不确定数量的参数。我们可以在函数定义中使用rest参数,将传入的多个参数包装成一个数组。通过 rest参数,我们可以方便地处理不定数量的函数参数,而不需要使用复杂的技巧。在函数参数列表中,rest 参数必须是最后一个参数,并且只能有一个。
-
什么是 ES6 新增的模板语法?
-
ES6 新增了哪些字符串处理函数?
ES6 为 string对象添加了一些新的方法,以便于处理字符串数据,以下列举一些常用的:
- includes():是否包含另一个字符串。
- trim():去除字符串两端的空格。
- repeat():将原字符串重复 n次。
- replaceA11():将所有匹配的字符串替换为新字符串。
- split():根据指定的分隔符,将字符串分割成数组,并可指定返回的数组长度。
- slice():与 substring 类似,截取指定位置的字符串,具体区别看扩展。
- substring():与 slice 类似,都是用来截取字符串,具体区别看扩展。
- startswith():判断是否以某个字符串开头;endswith():是否以某个字符串结尾。
- charAt()获取指定索引的字符
- charCodeAt()获取字符编码