一、Promise
1.promise是什么?
异步编程的解决方案
2.promise的出现?
解决异步编程的回调地狱问题
3.promise详解
promise是一个对象,代表一个异步操作,它有两个特征,三种状态(pengding、fulfilled/resolved、rejected),两个状态改变结果,即resolve和rejecte方法,它的原型上有then、catch、finally方法
4.promise与async/await
- async/await是消灭异步回调的终极武器,与promise相辅相成,async写在函数前边,await写在异步请求api函数前面,后面跟的promise
- 执行async函数返回的一定是promise对象,
- 在async修改的函数内部return一个值,可以在then回调函数中拿到
- await相当于promise的then,try…catch相当于promise的catch
- 首先,无法取消Promise,一旦新建它就会立即执行,无法中途取消。
- 其次,如果不设置回调函数,Promise内部抛出的错误,不会反应到外部
二、闭包
-
定义:能够访问到其他函数作用域中的对象的函数,称为闭包
-
什么是回调函数(callback)?
回调是作为参数传递给另一个函数并在其父函数完成后执行的函数
<script>
function doSomething(msg, callback) {
alert(msg);
if (typeof callback == "function")
callback();
}
doSomething("回调函数", function() {
alert("匿名函数回调!");
});
</script>
<script>
//定义主函数,回调函数作为参数
function A(callback) {
callback();
console.log('我是主函数');
}
//定义回调函数
function B() {
setTimeout("console.log('我是回调函数')", 3000); //模仿耗时操作
}
//调用主函数,将函数B传进去
A(B);
</script>
- 分析过程
-
全局执行上下文创建作用域链,作用域链包含了全局变量对象 [作用域链:[全局变量对象]]
-
books函数调用时创建作用域链,具体操作为先复制全局的作用域,然后创建活动对象AO推入当前作用域的顶端 [作用域链:[book活动变量, 全局变量对象]],books函数执行完毕后当前作用域会被销毁
-
bag函数调用创建作用域,首先复制上层作用域[作用域链:[book活动变量, 全局变量对象]],然后创建活动对象AO推入当前作用域的顶端[作用域链:[匿名函数func, book活动变量, 全局变量对象]],bag函数执行完毕后当前作用域会被销毁
- 闭包为什么会造成内存的泄露?
内存的泄露指应该被清除而没有被清除
能够访问到其他函数作用域中的对象的函数,称为闭包
面试中常问到的问题
1.如何在外部访问函数作用域内的变量,请手写一段代码进行验证
2.分析一道面试题
// function fn() {
// var arr = []
// for (var i = 0; i< 10; i++) {
// arr[i] = function() {
// return i
// }
// }
// return arr
// }
function fn() {
var arr = []
for (var i = 0; i< 10; i++) {
(function(i){
arr[i] = function() {
return i
}
})(i)
}
return arr
}
var arr = fn()
console.log(arr[0]())
var arr = fn()
console.log(arr[0]())
- 自调用函数?
自调用函数即立即执行函数,多个立即执行函数需要加分号
(function(){})() //写法1:括号外调用
(function(){}()) //写法2:括号内调用
三、作用域
简记忆:作用域规定了能够被访问的范围,分全局、局部(函数)、、
ES6中的全局作用域
ES6中的局部(函数)作用域
ES6中的块级作用域
//es6前js没有块级作用域
if (true) {
var a = 1 //ES6之前使用var声明的变量会存在变量提升,它们的作用域是函数作用域或者全局作用域.即// window.a
}
console.log(a) //结果:1
function fn () {
if (true) {
var a = 2 //变量a只存在于if语句块内部,所以在块外部无法访问
}
console.log(a) //结果:undefined
}
//es6后引入了let和const关键字,它们可以在声明的块(如if语句、for循环等)内创建块级作用域,与其他作用域一样,对外是不可见的
if (true) {
let x = 1 //使得代码更加可控和可靠。开发者可以更好地管理变量的作用域,避免变量冲突和意外的副作用
}
console.log(x) //结果: Uncaught ReferenceError: x is not defined
四、作用域链
作用域链的用途,是保证对执行环境有权访问的所有变量和函数的有序访问。
var a = 1
function fn () {
var b = a + 1
console.log(b)
}
fn()
从代码执行来看
首先在创建fn函数时,会创建一个预先包含全局变量对象的作用域链,这个作用域链被保存在内部的[[Scope]]属性中。/当调用fn函数时,会为函数创建一个执行环境,然后通过复制函数的[[Scope]]属性中的对象构建起执行环境的作用域链,然后创建活动对象AO并推入执行环境的作用域链。/在fn执行完成后,作用域就会被销毁。