xdm,放心食用(≧︶≦))( ̄▽ ̄ )ゞ! ! !
5. call() 、 apply() 、 bind() 三者的 用法和区别?
call(): func.call(thisArg, arg1, arg2)
apply(): func.apply(thisArg, [arg1, arg2,…])
bind(): func.bind(thisArg, arg1, arg2…)
三者的区别:
- 三者都可以改变函数的this对象指向。
- 三者第一个参数都是this要指向的对象,如果没有这个参数或参数为undefined或者null,则默认指向全局window。
- 三者都可以传参,但是apply传入的是数组,而call是参数列表,且call和apply是一次性传入参数,而bind可以分为多次传入。
- bind是返回绑定this之后的函数,不会立即执行;apply和call则是立即执行。
6. 作用域和作用域链?
作用域分为全局作用域(在代码的最外层定义的作用域,可以在整个应用程序中访问)、函数作用域(函数内部的变量和函数),块作用域(通过 let
和 const
声明的变量具有块级作用域,var声明的没有)。作用域链(Scope Chain)是 JavaScript 中用于处理变量访问的一种机制,作用域链本质上是【最底层的变量查找机制】,在函数被执行时,会优先查找在当前作用域中查找变量,如果当前作用域查找不到则会依次逐级查找父作用域直到全局作用域(嵌套关系的作用域串联起来形成了作用域链,子作用域能够访问父作用域,父作用域无法访问子作用域)
7.什么是闭包?
闭包简单来说可以理解为内层函数 + 外层函数变量,JS中内层函数可以访问外层函数的变量,使内部私有变量不受外界干扰,起到保护和保存的作用,我们把这个特性称作闭包。创建闭包通常有两种方式,一种是通过函数内部定义另外一个函数实现,另一种是通过立即执行函数表达式(IIFE)来创建闭包,这种方式通常用于创建私有变量。如果闭包引用的变量不再需要,但闭包仍然存在,可能会导致内存泄漏问题。
闭包的特点:
-
闭包可以访问其外部函数作用域中的变量,即使外部函数已经执行完毕。
-
由于闭包持有对外部变量的引用,这些变量将不会被垃圾回收机制回收,直到闭包不再被引用。
-
闭包可以用来创建私有变量,这些变量不能从外部直接访问。
function addCount() { let count = 0 return function () { count++ console.log(count) } } const fn = addCount() //外部函数已经执行完毕 fn() //fn()等于addCount()()
8. Promise & async / await 异步编程
Promise,简单来说就是一个容器,里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。语法上讲,Promise就是一个对象,Promise对象是一个构造函数,用来生成Promise实例,从该对象中可以获取异步操作的消息。Promise有三种状态:Pending(进行中)、Fulfilled/Resolved(已成功,下文统一使用Resolved)、Rejected(已失败)。
Promise对象有两个特点:
- 对象的状态不受外界影响, 只有异步操作的结果会决定当前是哪一种状态,任何其他操作都无法改变这个状态。
- 一旦状态发生改变就不会再变,任何时候都可以得到这个结果(状态改变:Pending --> Resolved /Rejected)
Promise对象有三个缺点:
-
无法取消Promise,一旦新建它就会立即执行,无法中途取消。
-
如果不设置回调函数,Promise内部抛出的错误不会反应到外部。
-
当Promise处于Pending状态时,无法得知当前进行到哪个阶段。
//Promise构造函数接受一个回调函数作为参数,该函数的两个参数为resolve和reject函数 //注意:调用resolve 和 reject 函数并不会终结Preomise的参数函数的执行(直白点就是resolve和reject之后还能执行语句,但是不建议。当调用这两个函数之一时,Promise的使命就完成了,后续应该在.then()方法里面处理。) //还有注意的一点就是Promise新建后会立即执行,然后执行同步任务,最后才执行then方法里面的回调函数 var promise = new Promise((resolve, reject) => { // ,,,some code if(/* 异步操作成功 */){ resolve(value) //成功时调用resolve函数将异步操作的结果作为参数传递出去 (Pending --> Resolved ) }else { reject(error) //失败时调用reject函数将报出的错误作为参数传递出去 (Pending --> Rejected ) } }) //接受两个回调作为参数, 第一个回调状态变为Resolved时调用,第二回调状态变为rejected时调用(可选参数) promise.then((value) => { //success },(error) => { //failure })
Promise.prototype.then()
then方法是定义在原型对象上的。它的作用就是为Promise实例添加状态改变时的回调函数。then方法返回的是一个新的Promise实例(不是原来的哪个Promise),所以可以接着.then()进行链式调用,使得多个异步操作可以顺序执行
//Es6 箭头函数写法 getJson("/post/1.json") .then(post => getJson(post.commentUrl)) //返回的还是一个Promise .then(comments => console.log("resolved:",comments), error => console.log("rejected:",error))
Promise.prototype.catch()
Promise.prototype.catch()方法是
.then(null, rejection)
的别名,用于指定发生错误时的回调函数。Promise
只要抛出一个错误就会别catch
方法指定的回调函数所捕获。promise .then(val => console.log("resolved:", val)) .catch(err => console.log("rejected:", error)) //等价于下面 promise .then(val => console.log("resolved:", val)) .then(null, err => console.log("rejected:", error)) //注意点: //假设Promise的状态已经变成resolved,即如果在resolve函数后面再抛出错误,将不会被捕获,等于没有抛出 //Promise对象的错误具有“冒泡”的性质,会一直向后传递,知道被捕获为止,所以为了.catch()方法后面的.then方法产生的错误不会被捕获问题,一般再所有.then方法执行完后调用.catch方法
Promise.all()
Promise.all方法用于将多个Promise实例包装成一个新的Promise实例
var p = Promise.all([p1, p2, p3,...]) // p1, p2, p3 都是Promise对象实例,如果不是,会调用Promise.resolve方法,将参数转为Promise实例 //p的状态取决于p1, p2, p3,只有当三个的状态都为Resolved,p的状态才会变成Resolved,此时p1,p2,p3的返回值组成一个数组,传递给p的回调 //p1,p2,p3中只要有一个被Rejected,p的状态就为Rejected,此时第一个被Rejected的实例的返回值会传递给p的回调函数 //注意点:如果作为参数的Promise实例自身定义了catch方法,那么它被rejected时并不会触发Promise.all()的catch方法
Promise.race()
Promise.race方法用于将多个Promise实例包装成一个新的Promise实例,但是和Promise.all的区别就是只要当
p1, p2, p3
中有一个实例状态先发生变化,p的状态就跟着改变。率先改变的Promise实例的返回值就传递给p
的回调函数.上面主要是一些Promise常用的方法,还有resolve,reject,done,finally等方法,大家有兴趣的话可以自己去看看💙💚💛ES6标准入门(第三版)
Async/Await
async/await
是基于Promise
的语法糖,它让异步代码看起来像同步代码一样。async
关键字用于声明一个函数将返回一个Promise
,而await
关键字用于等待Promise
解析。const fetchUserData = async () => { //我们通常会用try...catch包裹一下来处理错误 try { const responseData = awit fetch('https://api.example.com/user') const data = await responseData.json(); //....some code }catch (error) { console.log("错误了:"error) } }
注意事项:
async
函数总是返回一个Promise
await
只能在async
函数内使用- 如果
await
的表达式不是一个Promise
,那么它会被转换为一个解析过的Promise
- 如果
await
的Promise
被拒绝,那么await
后面的代码不会被执行,而是抛出一个异常,可以使用try...catch
来捕获这个异常