1.let,var ,const的区别
回答这个问题要从一下几个方向去回答:
1.块级作用域:let和const具有块级作用域,var不存在块级作用域的概念。块级作用域解决了ES5的两个问题:内层变量可能覆盖外层变量和循环时泄露循环变量为全局变量
2.变量提升:var 存在变量提升,let和const不存在变量提升(只能在声明后使用),涉及到上下文的概念
3.给全局添加属性:在全局window下,var声明的变量是全局变量,并将变量添加到全局对象的属性上,而let和const不会。
4.重复声明:var可以重复声明,而let,const不行
5.暂时性死区:在没有声明之前,let和const的变量都是不可用的,当然这作用于块级作用域内
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。
6.初始值设置:let和var可以不指定初始值,但是const必须指定初始值
7.指针指向:let创建的变量可以改变指针指向,但是const声明的变量不允许改变指针的指向。
2.const对象的属性可以修改吗?
const能保证的并不是变量的值不能改动,而是变量指向的内存地址不能改动。那么对于基本类型的数据来说,其值保存在变量指向的内存地址中,所以不能改变。相当于常量;
然而当我们变量是指向引用类型的地址时,此时我们的const只能保证它指向的地址指针不能改动,但是对于它内存中的内容我们就无法控制了。
3.如果new一个箭头函数会怎样?
首先说一下new操作符的实现步骤:
- 创建一个新的对象
- 然后将构造函数的作用域赋给新对象(也就是将对象的
__proto__
属性指向构造函数的prototype属性) - 构造函数中的this指向该对象并且执行
- 返回新的对象
回看这个问题,箭头函数时ES6提出的,它本身没有prototype属性,也没有自己的this指向,也没有argument参数。因此它不具备new一个实例对象的条件**,因此如果直接new一个箭头函数的话会报错。报箭头函数不是一个构造函数的错误**
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-i2OlDX2Z-1625298349325)(C:\Users\LuAo\AppData\Roaming\Typora\typora-user-images\image-20210613152755570.png)]
4.箭头函数和普通函数的区别
1.箭头函数比普通函数更加简洁
2.箭头函数没有自己的this
箭头函数的this总是指向它当前作用域的上一层
var id = 'GLOBAL';
var obj = {
id: 'OBJ',
b: () => {
console.log(this.id);
}
};
obj.b(); // 'GLOBAL'
复制代码
3.箭头函数继承来的this指向永远不会改变
4.call()、apply()、bind()等方法不能改变箭头函数中的this指向
5.箭头函数不能作为构造函数使用
6.箭头函数没有自己的arguments
7.箭头函数没有prototype属性
8.箭头函数不能用作Generator函数,不能使用yeild关键字
5.箭头函数的this指向哪里?
箭头函数实际上并没有属于自己的this,它的this实际上时继承了所处作用域的上级的this作为自己的this值。这个this在定义时就已经确定下来,之后也不会改变。
可以使用babel将es6代码转为es5代码理解一下this:
ES6:
const obj = {
getArrow() {
return () => {
console.log(this === obj);
};
}
}
复制代码
Babel编译后:
// ES5,由 Babel 转译
var obj = {
getArrow: function getArrow() {
var _this = this;
return function () {
console.log(_this === obj);
};
}
};
复制代码
6.扩展运算符的作用及适用场景?
1.对象的扩展运算符
对象的扩展运算符用于取出对象所有可遍历的属性,拷贝到当前的对象中。
let a = {name: 'a',age: 12}
let b = { ...a }
复制代码
其实扩展运算符等价于Object.assign()
let a = {name: 'a',age: 12}
let b=Object.assign({},a)
复制代码
Object.assign()
方法用于方法的合并,将源对象的所有可枚举枚举的属性复制到目标对象中。
它的第一个参数时目标对象,后面的参数都是源对象
一个对象扩展运算符的适用场景,在redux的reducer中要求reducer函数必须是一个纯函数,即我们不能直接在函数内部操作state状态,所以我们可以适用扩展运算符对其直接进行拷贝产生一个新的对象进行返回
注意:扩展运算符和对象实例的拷贝都是浅拷贝
2.数组扩展运算符
数组扩展运算符可以将一个数组转为用逗号分隔的参数序列,且每次只能展开一层数组。
应用场景:
- 将数组转换为参数序列
- 复制数组
- 合并数组
- 与结构赋值结合起来用于产生新的数组(注:使用扩展运算符用于数组赋值,其只能放在最后一位,否则报错)
- 将字符串转为数组**(算法题可用)**
- 将参数列表argument转化为数组(代替了
Array.prototype.slice.call(arguments)
)
7.对象与数组的结构的理解?
其实就是有针对性的在数组和对象中拿取数据,其中数组时按照位置取值,对象时按照属性名名称取值,与位置无关。
在对象的解构中有时候会碰到高度嵌套的对象,这时我们如果想要提取属性时就又有一种特别的写法:{解构出来的对象:{下一层对象:{目标属性}}}
例如:
const school = {
classes: {
stu: {
name: 'Bob',
age: 24,
}
}
}
复制代码
如果我们想要取到name:
let {classes:{stu:{name}}}=school
复制代码
8.对rest参数的理解?
将函数的形参整个成一个数组,经常用于处理不确定函数参数个数的情况。
function mutiple(...args) {
console.log(args)
}
mutiple(1, 2, 3, 4) // [1, 2, 3, 4]
复制代码
10.object.assign和es6的扩展运算符是深拷贝还是浅拷贝,两者有何区别
两者都是浅拷贝。
共同点:
共同点是都是取复制旧的对象进而去创建该对象的一个副本,且都是浅拷贝
不同点:
Object.assign
函数修改其第一个传入的tartget对象,因此会触发es6的setter,修改set后如果我们使用了Proxy或者Object.defineProperty在set方法上进行其他操作,那我们就会碰到意想不到的错误- 而扩展运算符给我们一个普通的JavaScript对象,对我们后续操作并不会有什么影响