1、let与var的区别
var
- 使用var生命的变量拥有函数作用域和全局作用域
- 可以不声明就使用
- 相同的作用域,允许声明重名的变量
let
- 使用let声明的变量拥有块级作用域,全局作用域
- 必须先声明后使用(在被声明之前的区域被称为暂时性死区)
- 相同的作用域,不允许声明重名的变量
典型代码示例
for(var i =0;i<5;i++){
setTimeout(function() {
console.log(i);
}, 100*i);
}
//打印 5 5 5 5 5
//解释:这里所有的i都在同一个作用域内,外加setTimeout函数是异步的
//当它执行的时候i已经叠加到5了,所以之后的setTimeout都打印5
//解决方案1(使用自执行函数包裹一层)
for(var i=0;i<5;i++){
(
function(i){
setTimeout(function() {
console.log(i);
}, i*100);
}
)(i)
}
//解决方案2(使用es6新关键字let)
for(let i =0;i<5;i++){
setTimeout(function() {
console.log(i);
}, 100*i);
}
//结论:
//方案1 使用自执行函数,自执行函数的参数i会覆盖会覆盖for循环的i
//方案2 使用let声明的变量拥有块级作用域,for循环每次迭代的时候,都会创建一个新的作用域
//现在看来不管是方案1还是方案2,都做了相同的事情,就是在每一次迭代的时候都要让 i 拥有不同的作用域。
2、 Promise 中 .then 的第二参数与 .catch 有什么区别?
当使用then方法进行链式调用的时候,每一个then方法发生异常都会被最后一个.catch方法捕获
xmlRequest(url).then(data => {
}).then(r=>{
}).then(r=>{
}).catch(err=>{
//之前几个promise的发生异常时,都会被最后一个catch捕获到
})
promise
.then(function(data) {
// success
}, function(err) {
// error
});
// good
promise
.then(function(data) { //cb
// success
})
.catch(function(err) {
// error
});
一般来说,不要在then方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。
3、Object与Map的异同
-
Object
和Map
类似的是,它们都允许你按键存取一个值、删除键、检测一个键是否绑定了值。因此(并且也没有其他内建的替代方式了)过去我们一直都把对象当成Map
使用。不过Map
和Object
有一些重要的区别,在下列情况里Map
会是更好的选择:
- 一个对象的键只能是
字符串
或者Symbols
,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"。"),但一个Map
的键可以是任意值,包括函数、对象、基本类型。 - 你可以通过
size
属性直接获取一个Map
的键值对个数,而Object
的键值对个数只能手动计算。 -
Map
是可迭代的,而Object
的迭代需要先获取它的键数组然后再进行迭代。 -
Object
都有自己的原型,所以原型链上的键名有可能和对象上的键名产生冲突。虽然 ES5 开始可以用map = Object.create(null)
来创建一个没有原型的对象,但是这种用法不太常见。 - Map 在涉及频繁增删键值对的场景下会有些性能优势。