ES6相关芝士点
ES6相关芝士点
1、let、const、var的区别
作用域
var 声明的变量具有函数作用域或全局作用域。
函数作用域:如果在函数内使用 var 声明变量,则该变量只在这个函数内有效。
let 和 const 声明的变量具有块级作用域。
块级作用域:由大括号 {} 包含的区域。
变量提升
变量提升:将变量是或者函数声明提升到所在作用域顶部的行为。
var 声明的变量会被提升到函数作用域或全局作用域顶部,但只提升声明,不提升赋值。
1 |
|
let 和 const 声明的变量也会被提升到块级作用域的顶部,但处于暂时性死区状态!不会被初始化,因此这时候访问它会抛出ReferenceError
错误!
暂时性死区:变量处于不可访问状态。
全局属性
在全局作用域中用 var 声明的变量,会自动成为全局对象的一个属性。
容易与其他全局属性冲突,增加全局命名空间的负担。
在全局作用域中用 let 和 const 声明的变量,不会附加到全局对象上。
重复声明
在同一作用域内,使用 var 声明的变量,可以重复声明,后面会覆盖前面的值。
使用 let 和 const 声明的变量,如果在同一块级作用域内,重复声明会导致语法错误。如果在不同的块级作用域内,可以重复声明相同的变量名,不会冲突,因为作用域不同。
初始化
const 声明的变量必须在声明的同时初始化,否则会报语法错误。而且一旦声明和初始化后,变量的引用不能再被改变。如果引用的是一个对象或者数组,内部的属性或者元素仍然可以修改,但是变量本身不能重新被赋值。
var 和 let:可以不立即初始化,声明后默认值为 undefined
,并且后续可以赋值。
2、new操作符的原理?可以new箭头函数吗
1、创建一个空对象
2、设置原型:将新对象的内部[[Prototype]](也就是__proto__
)指向构造函数的prototype
属性。
3、执行构造函数:将新对象作为 this 上下文,调用构造函数,并将参数传递给构造函数。
4、返回值处理:如果构造函数显式返回的对象,直接返回。否则,默认返回新对象。
? 不能new箭头函数的原因
箭头函数没有自己的
this
,它们继承自外部作用域,因此不具备构造函数所需要的特性。箭头函数没有
prototype
属性,构造函数需要这个属性来构建实例的原型链。
1 |
|
3、箭头函数与普通函数的区别
this的绑定
箭头函数
箭头函数没有自己的this,是词法绑定,即继承它定义时候的所在上下文(词法环境)的this值。
无论怎么调用,箭头函数的this是固定的,固定的,不会再变。
1
2
3
4
5
6
7const obj = {
value: 42,
arrow: () => {
console.log(this); // this 指向外部环境(例如全局对象或父函数的 this),而不是 obj
}
};
obj.arrow(); // 可能输出 window(在浏览器中)或 undefined(在严格模式下)普通函数
普通函数的this是动态绑定,取决于它的调用方式。
对象的方法中调用,this指向对象;
函数通过new关键字调用,this绑定到新创建的实例对象;
直接调用,指向全局对象(非严格)或者undefiend(严格);
通过call、apply、bind调用,显式指定调用时的this值。
1
2
3
4
5
6
7const obj = {
value: 42,
method: function() {
console.log(this); // this 指向 obj
}
};
obj.method(); // 输出 obj
?this是什么
在JavaScript中,
this
是一个非常重要的关键字,它在函数被调用时被赋予一个值,用来指向函数执行的上下文环境(即“谁”在调用这个函数)。它的值通常是一个对象,但具体指向哪个对象取决于函数的调用方式。
- 作为方法调用:
this
指向调用它的对象。- 作为普通函数调用:
this
指向全局对象(非严格模式)或undefined
(严格模式)。- 作为构造函数调用:
this
指向新创建的对象实例。- 通过
call
、apply
或bind
调用:this
指向显式指定的对象。- 箭头函数中:
this
捕获定义时所在上下文的this
值。
arguments对象
箭头函数
没有自己的
arguments
对象。箭头函数内部的
arguments
会从其定义时所在的词法作用域继承而来。1
2
3
4
5
6
7function outer() {
const arrow = () => {
console.log(arguments); // 引用的是 outer 函数的 arguments
};
arrow();
}
outer(1, 2, 3); // 输出 [1, 2, 3]普通函数
有自己的
arguments
对象,包含了传入函数的所有参数。1
2
3
4function normal() {
console.log(arguments); // 输出传入的参数对象
}
normal(1, 2, 3); // 输出 [1, 2, 3]
用作构造函数
箭头函数
不能用作构造函数,无法使用
new
操作符调用,因为它们没有内部的[[Construct]]
方法,也没有prototype
属性。1
2const Arrow = () => {};
// new Arrow(); // TypeError: Arrow is not a constructor普通函数
可以用作构造函数,通过
new
调用后,会创建一个新对象,并将其绑定到函数内部的this
上。1
2
3
4
5function Person(name) {
this.name = name;
}
const p = new Person("Alice");
console.log(p.name); // "Alice"
prototype属性
箭头函数
不存在
prototype
属性,因为它们不能作为构造函数。普通函数
拥有
prototype
属性,当函数被用作构造函数时,该属性会成为新创建对象的原型。
4、扩展运算符的作用及使用场景
ES6引入的语法,…主要是把可迭代对象(数组、字符串、Set、Map等)或者对象展开为单独的元素或者属性。
数组合并、数组复制
1 |
|
? 浅拷贝的含义
浅拷贝仅复制数组的第一层,引用类型元素与原数组共享内存。
修改基本类型(不影响原数组),修改引用类型的内容(影响原数组)
但替换整个元素(改变引用)不会影响原数组。
函数参数传递
参数存储在数组中时,可以使用扩展运算符将数组转换为一个参数列表。
1 |
|
? 和rest运算符的区别
rest 运算符(使用三个点
...
)用于将多个数据“收集”成一个数组或对象,主要应用在函数参数和解构赋值中。它与扩展运算符(spread operator)共享相同的语法,但语义相反:
1
2
3
4
5
6
function sum(...numbers) {
// `numbers` 是一个数组,包含了所有传入的参数
return numbers.reduce((acc, curr) => acc + curr, 0);
}
console.log(sum(1, 2, 3, 4)); // 输出 10
对象合并、对象复制
将多个对象的属性合并到一个新对象中
1 |
|
利用扩展运算符进行浅拷贝,快速复制一个对象
1 |
|
解构赋值
用于提取剩余的数组元素或对象属性。
1 |
|
5、什么是解构
ES6提供的一种模式,用于从数组或对象提取数据,是一种语法糖。
数组解构
按顺序、默认值、跳过元素、嵌套解构
1 |
|
1 |
|
对象解构
以属性名为匹配条件!换顺序也可以提取!
1 |
|
也可以使用别名,默认值
1 |
|
? 如果是深度嵌套如何提取
1
2
3
4
5
6
7
8
const school = {
classes: {
stu: {
name: 'Bob',
age: 24,
}
}
}
1
2
3
const { classes: { stu: { name } }} = school
console.log(name) // 'Bob'
应用场景
函数参数使用解构提取数组或者对象的值
1 |
|
快速交换变量值(如果是引用类型,交换地址)
1 |
|
处理返回多个值的函数:
1 |
|
6、ES6中模板字符串语法
使用反引号来定义模版字面量:
1 |
|
支持多行字符串,无需特殊的转义字符。
在模板字符串中,空格、缩进、换行都会被保留(所以可以写HTML代码)
1 |
|
通过${}
进行字符串插值,可以嵌入任意表达式,在运行时计算并转为字符串:
1 |
|