es6相关面试题:1.rest参数;2.new.target;3.object.defineProperty与Proxy的区别;4.Reflect对象作用;5.lterator迭代器;6.async
文章目錄
- 說說對ES6中rest參數的理解
- 說說你對new.target的理解
- 談談object.defineProperty與Proxy的區別
- ES6中的Reflect對象有什么用?
- 簡單介紹下ES6中的lterator迭代器
- 如何理解async/await
說說對ES6中rest參數的理解
ES6 引入 rest 參數(形式為…變量名),用于獲取函數的多余參數,這樣就不需要使用arguments對象了。rest 參數搭配的變量是一個數組,該變量將多余的參數放入數組中。
function add(...values) {let sum = 0;for (var val of values) {sum += val;}return sum; }add(2, 5, 3) // 10上面代碼的add函數是一個求和函數,利用 rest 參數,可以向該函數傳入任意數目的參數。
下面是一個 rest 參數代替arguments變量的例子。
// arguments變量的寫法 function sortNumbers() {return Array.prototype.slice.call(arguments).sort(); }// rest參數的寫法 const sortNumbers = (...numbers) => numbers.sort();arguments對象不是數組,而是一個類似數組的對象。所以為了使用數組的方法,必須使用Array.prototype.slice.call先將其轉為數組。rest 參數就不存在這個問題,它就是一個真正的數組,數組特有的方法都可以使用。下面是一個利用 rest 參數改寫數組push方法的例子。
function push(array, ...items) {items.forEach(function(item) {array.push(item);console.log(item);}); }var a = []; push(a, 1, 2, 3)注意,rest 參數之后不能再有其他參數(即只能是最后一個參數),否則會報錯。
箭頭函數不可以使用arguments對象,該對象在函數體內不存在。如果要用,可以用 rest 參數代替
說說你對new.target的理解
new.target屬性允許你檢測函數或構造方法是否是通過new運算符被調用的。
在通過new運算符被初始化的函數或構造方法中,new.target返回一個指向構造方法或函數的引用。在普通的函數調用中,new.target 的值是undefined。
我們可以使用它來檢測,一個函數是否是作為構造函數通過new被調用的。
談談object.defineProperty與Proxy的區別
在 Vue2.x 的版本中,雙向綁定是基于 Object.defineProperty 方式實現的。而 Vue3.x 版本中,使用了 ES6 中的 Proxy 代理的方式實現。
Object.defineProperty(obj, prop, descriptor)
使用 Object.defineProperty 會產生三個主要的問題:
1.不能監聽數組的變化
2.必須遍歷對象的每個屬性
可以通過 Object.keys() 來實現
3.必須深層遍歷嵌套的對象
通過遞歸深層遍歷嵌套對象,然后通過 Object.keys() 來實現對每個屬性的劫持
Proxy
Proxy 針對的整個對象,Object.defineProperty 針對單個屬性,這就解決了 需要對對象進行深度遞歸(支持嵌套的復雜對象劫持)實現對每個屬性劫持的問題
Proxy 解決了 Object.defineProperty 無法劫持數組的問題
比 Object.defineProperty 有更多的攔截方法,對比一些新的瀏覽器,可能會對 Proxy 針正對性的優化,有助于性能提升
ES6中的Reflect對象有什么用?
Reflect 對象不是構造函數,所以創建時不是用 new 來進行創建。
在 ES6 中增加這個對象的目的:
1.將 Object 對象的一些明顯屬于語言內部的方法(比如 Object.defineProperty),放到 Reflect 對象上。現階段,某些方法同時在 Object 和 Reflect 對象上部署,未來的新方法將只部署在 Reflect 對象上。也就是說,從 Reflect 對象上可以拿到語言內部的方法。
2.修改某些 Object 方法的返回結果,讓其變得更合理。比如,Object.defineProperty(obj, name, desc)在無法定義屬性時,會拋出一個錯誤,而 Reflect.defineProperty(obj, name, desc)則會返回 false。
3.讓 Object 操作都變成函數行為。某些 Object 操作是命令式,比如 name in obj 和 delete obj[name],而 Reflect.has(obj, name)和 Reflect.deleteProperty(obj, name)讓它們變成了函數行為。
4.Reflect 對象的方法與 Proxy 對象的方法一一對應,只要是 Proxy 對象的方法,就能在 Reflect 對象上找到對應的方法。這就讓 Proxy 對象可以方便地調用對應的 Reflect 方法,完成默認行為,作為修改行為的基礎。也就是說,不管 Proxy 怎么修改默認行為,你總可以在 Reflect 上獲取默認行為。
var loggedObj = new Proxy(obj, {get(target, name) {console.log("get", target, name);return Reflect.get(target, name);},deleteProperty(target, name) {console.log("delete" + name);return Reflect.deleteProperty(target, name);},has(target, name) {console.log("has" + name);return Reflect.has(target, name);}, });上面代碼中,每一個 Proxy 對象的攔截操作(get、delete、has),內部都調用對應的 Reflect 方法,保證原生行為能夠正常執行。添加的工作,就是將每一個操作輸出一行日志。
簡單介紹下ES6中的lterator迭代器
Iterator迭代器的出現就是為了迭代而生,為不同的集合:Object、Array、Map、Set,提供了一個統一的接口(這里接口可以簡單的理解為方法,就是遍歷方法)
Iterator迭代器就是一個接口方法,它為不同的數據結構提供了一個統一的訪問機制;使得數據結構的成員能夠按某種次序排列,并逐個被訪問。
要成為可迭代對象, 一個對象必須實現iterator方法。這意味著對象(或者它原型鏈上的某個對象)必須有一個鍵為iterator的屬性,可通過常量 Symbol.iterator 訪問該屬性。
將myIterable對象添加Symbol.iterator屬性,同時在返回的next方法中,添加兩個屬性,既讓它成為了一個可迭代對象。(其實如果真的有這樣的需求,可以考慮使用Map)。
Iterator規范————Iterator迭代器包含一個next()方法,方法調用返回返回兩個屬性:done和value;通過定義一個對象的Symbol.iterator屬性,即可將此對象修改為迭代器對象,支持for…of遍歷。
如何理解async/await
使用 Promise 能很好地解決回調地獄的問題,但如果處理流程比較復雜的話,那么整段代碼將充斥著 then,語義化不明顯,代碼不能很好地表示執行流程
async/await是比 Promise 更優雅的異步方式
前面添加了async的函數在執行后都會自動返回一個Promise對象:
添加async后
async function foo() {return 'jimmy' // Promise.resolve('jimmy') } console.log(foo()) // Promise foo()async函數中使用await,那么await這里的代碼就會變成同步的了,意思就是說只有等await后面的Promise執行完成得到結果才會繼續下去,await就是等待。
function timeout() {return new Promise(resolve => {setTimeout(() => {console.log(1)resolve()}, 1000)}) }// 不加async和await是2、1 加了是1、2 async function foo() {await timeout() console.log(2) } foo()使用場景
假如有這樣一個使用場景:需要先請求 a 鏈接,等返回信息之后,再請求 b 鏈接的另外一個資源。下面代碼展示的是使用 fetch 來實現這樣的需求,fetch 被定義在 window 對象中,它返回的是一個 Promise 對象
雖然上述代碼可以實現這個需求,但語義化不明顯,代碼不能很好地表示執行流程。基于這個原因,ES8 引入了 async/await,這是 JavaScript 異步編程的一個重大改進,提供了在不阻塞主線程的情況下使用同步代碼實現異步訪問資源的能力,并且使得代碼邏輯更加清晰。
通過上面代碼,你會發現整個異步處理的邏輯都是使用同步代碼的方式來實現的,而且還支持 try catch 來捕獲異常,這感覺就在寫同步代碼,所以是非常符合人的線性思維的。
注意點
●await 只能在 async 標記的函數內部使用,單獨使用會觸發 Syntax error。
●await后面需要跟異步操作,不然就沒有意義,而且await后面的Promise對象不必寫then,因為await的作用之一就是獲取后面Promise對象成功狀態傳遞出來的參數。
async/await的缺陷
Async/await 讓你的代碼看起來是同步的,在某種程度上,也使得它的行為更加地同步。 await 關鍵字會阻塞其后的代碼,直到promise完成,就像執行同步操作一樣。它確實可以允許其他任務在此期間繼續運行,但您自己的代碼被阻塞
這意味著您的代碼可能會因為大量await的promises相繼發生而變慢。每個await都會等待前一個完成,而你實際想要的是所有的這些promises同時開始處理(就像我們沒有使用async/await時那樣)
總結
以上是生活随笔為你收集整理的es6相关面试题:1.rest参数;2.new.target;3.object.defineProperty与Proxy的区别;4.Reflect对象作用;5.lterator迭代器;6.async的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java毕业论文云笔记_java毕业设计
- 下一篇: 问题排除:电机摩擦力怎么计算?