Javascript

原型鏈的理解

  • 看一個(gè)實(shí)例
var animal = function() {};
var dog = function() {};
animal.prototype.price = 20;
animal.price = 1000;
dog.prototype = animal;

var cat = new animal();
var tidy = new dog();
// 下面兩行分別輸出什么僚纷?
console.log(cat.price);
console.log(tidy.price);
  • 原型和原型鏈?zhǔn)紫纫缼讉€(gè)概念:

    • 在js里嫂便,繼承機(jī)制是原型繼承楼熄。繼承的起點(diǎn)是 對(duì)象的原型(Object prototype)忆绰。
    • 一切皆為對(duì)象,只要是對(duì)象可岂,就會(huì)有 proto屬性错敢,該屬性存儲(chǔ)了指向其構(gòu)造的指針。
    • Object prototype也是對(duì)象缕粹,其 proto指向null稚茅。
    • 對(duì)象分為兩種:函數(shù)對(duì)象和普通對(duì)象,只有函數(shù)對(duì)象擁有『原型』對(duì)象(prototype)平斩。
    • prototype的本質(zhì)是普通對(duì)象亚享。
    • Function prototype比較特殊,是沒有prototype的函數(shù)對(duì)象绘面。
    • new操作得到的對(duì)象是普通對(duì)象欺税。
  • 當(dāng)調(diào)取一個(gè)對(duì)象的屬性時(shí),會(huì)先在本身查找揭璃,若無晚凿,就根據(jù) proto找到構(gòu)造原型,若無瘦馍,繼續(xù)往上找歼秽。最后會(huì)到達(dá)頂層Object prototype,它的 proto指向null情组,均無結(jié)果則返回undefined燥筷,結(jié)束。

  • 由 proto 串起的路徑就是『原型鏈』院崇。


    image
  • cat調(diào)用price
    ① 查看本身荆责,沒有price,根據(jù) proto找到 animal prototype對(duì)象亚脆。
    ② 在animal prototype對(duì)象中找到了price做院,所以 cat.price 結(jié)果為20。
    ③ 如果無 animal.prototype=20濒持,則會(huì)根據(jù)animal prototype對(duì)象的 proto 找到Object prototype键耕,Object prototype的proto指向null娜搂,若仍沒有找到price坠陈,結(jié)果則為undefined琳拨。

  • tidy調(diào)用price
    ① 查看本身斋竞,沒有price吐辙,根據(jù) proto找到dog prototype派撕。
    ② dog prototype = animal关摇,這里可以這樣理解:prototype本質(zhì)也是一個(gè)對(duì)象屑埋,因此可以重新賦一個(gè)對(duì)象,無論是函數(shù)對(duì)象還是普通對(duì)象惋嚎。事實(shí)上杠氢,每個(gè) prototype 會(huì)有一個(gè)預(yù)定義的constructor屬性用來引用它的函數(shù)對(duì)象。
    ③ 在animal中找到了price另伍, 所以 tidy.price 結(jié)果為1000鼻百。
    ④ 如果無 animal.price = 1000,則會(huì)根據(jù)animal的proto找到下一個(gè)對(duì)象摆尝,最終都沒有找到 price温艇,結(jié)果就為undefined。

  • 深入

    • 創(chuàng)建一個(gè)對(duì)象的方式
      • {}堕汞、new Object()
      • 構(gòu)造函數(shù)
      • Object.create()
        此方法將新對(duì)象的proto更改并指向create的入?yún)?duì)象勺爱。
    • instance of VS constructor
      • instance of 原理:檢查左邊對(duì)象與右邊對(duì)象是否在同一條原型鏈上。
      • constructor原理:取對(duì)象的proto屬性指向的prototype對(duì)象上的constructor字段讯检。
cat instanceof animal === true
cat.__proto__ === animal.prototype

animal.prototype instanceof Object === true
animal.prototype.__proto__ === Object.prototype

cat instanceof Object === true
// but琐鲁,
cat.constructor === animal // true
cat.constructor === Object // false
  • new運(yùn)算符的原理
    • 創(chuàng)建一個(gè)空對(duì)象,它的proto等于構(gòu)造函數(shù)的原型對(duì)象(可以用Object.create()完成)
    • 構(gòu)造函數(shù)以第1步創(chuàng)建的對(duì)象做為上下文视哑,是否會(huì)返回一個(gè)對(duì)象
    • 若第2步返回了對(duì)象绣否,則使用該對(duì)象作為新實(shí)例,否則用第1步創(chuàng)建的對(duì)象作為新實(shí)例
var myNew = function (func) {
var o = Object.create(func.prototype)
var i = func.call(o)
return typeof i === 'object' ? i : o
}

  • 繼承

    • 類的聲明
      • function
      • class
  • 生成實(shí)例:new

  • 繼承的幾種方式:

    • 借助構(gòu)造函數(shù)挡毅,父類的作用域指向子類
    • Parent.call(this) // this是Child類的上下文
    • 缺點(diǎn):不能繼承原型鏈屬性
    • 借助原型鏈
      • Child.prototype = new Parent()
      • 缺點(diǎn):子類所有實(shí)例共享原型對(duì)象蒜撮;子類實(shí)例的constructor為Parent
  • 組合方式

    • Parent.call(this) // this是Child類的上下文
    • Child.prototype = Object.create(Parent.prototype)
    • Child.prototype.constructor = Child

.bind()、.live()跪呈、.delegate()和.on()之間的區(qū)別

  • bind
    .bind()方法將會(huì)把事件處理函數(shù)連接到所有匹配的標(biāo)簽段磨。這種方式并不好。這樣做的話耗绿,它不僅在所有匹配的元素中隱含地迭代附加事件處理函數(shù)苹支,而且這些操作非常浪費(fèi)(多余),因?yàn)檫@些相同的事件處理函數(shù)是被一遍一遍的重復(fù)的添加到所有匹配的標(biāo)簽上误阻。
    • 優(yōu)點(diǎn):
      • 適用于各種瀏覽器
      • 連接事件處理函數(shù)非常方便快捷
      • 可以使用 .click() , .hover()等簡(jiǎn)寫方法來更方面地連接事件處理函數(shù)
      • 對(duì)于一個(gè)簡(jiǎn)單的ID選擇器,使用.bind() 方法不僅可以很快地連接事件處理函數(shù),而且當(dāng)事件被觸發(fā)時(shí), 事件處理函數(shù)幾乎是馬上就被調(diào)用了
    • 缺點(diǎn):
      • 這樣方法會(huì)將所有的事件處理函數(shù)附加到所有匹配的元素
      • 不可以動(dòng)態(tài)地匹配相同選擇器的元素
      • 當(dāng)操作大量匹配的元素時(shí)會(huì)有性能方面的問題
      • 附加操作是在前期完成的,這可能導(dǎo)致頁面加載時(shí)存在性能問題
  • Live
    .live()方法使用了事件委托的概念來實(shí)施其所謂的“魔法”债蜜。你調(diào)用live()方法的方式就像是調(diào)用bind()方法那樣方便。然而在這表面之下究反, .live()方法與前者的實(shí)現(xiàn)方式大不相同寻定。 .live()方法將與事件處理函數(shù)關(guān)聯(lián)的選擇器和事件信息一起附加到文檔的根級(jí)元素(即document)。通過將事件信息注冊(cè)到document上精耐,這個(gè)事件處理函數(shù)將允許所有冒泡到document的事件調(diào)用它(例如委托型狼速、傳播型事件)。一旦有一個(gè)事件冒泡到document元素上卦停,Jquery會(huì)根據(jù)選擇器或者事件的元數(shù)據(jù)來決定哪一個(gè)事件處理函數(shù)應(yīng)該被調(diào)用向胡,如果這個(gè)事件處理函數(shù)存在的話恼蓬。這個(gè)額外的工作將會(huì)在用戶交互時(shí)對(duì)性能方面造成一定的影響,但是初始化注冊(cè)事件的過程相當(dāng)?shù)乜臁?/li>
/* 方法將與事件處理函數(shù)關(guān)聯(lián)的選擇器和事件信息一起附加到文檔的根級(jí)元素(即document)  ( "#members li a" & "click" ) */
$( "#members li a" ).live( "click", function( e ) {} );

.bind()這個(gè)例子與上面bind()方法的例子對(duì)比的話有一個(gè)優(yōu)點(diǎn)在于它僅僅把事件處理函數(shù)附加到document元素一次僵芹,而不是很多次处硬。這樣不僅更快,而且還減少了性能的浪費(fèi)淮捆。然而郁油,使用這個(gè)方法也會(huì)帶來很多問題本股,下面將一一列出攀痊。

  • 優(yōu)點(diǎn):

    • 所有的事件處理函數(shù)都只會(huì)被注冊(cè)一次,而不是像bind()那樣進(jìn)行多次注冊(cè)
    • 將bind()方法升級(jí)到live()方法非常方便拄显,你僅需要將"bind"替代為"live"就可以了
    • 那些被動(dòng)態(tài)添加到DOM的元素也將被神奇的匹配到苟径,因?yàn)檎鎸?shí)的事件信息是被注冊(cè)到document元素上的
      你可以在文檔加載完之前連接事件處理函數(shù),這樣可以幫助你更好地利用你可能沒有用的時(shí)間
  • 缺點(diǎn):

    • 這個(gè)方法在Jquery 1.7以后的版本被棄用了躬审,你應(yīng)該在你的代碼里逐步放棄使用它
    • 使用這個(gè)方法時(shí)鏈?zhǔn)讲僮鳑]有得到正確的支持棘街,可能會(huì)出現(xiàn)某些錯(cuò)誤
    • 所做的匹配操作基本上沒用因?yàn)樗挥糜谠赿ocument元素上注冊(cè)事件處理函數(shù)
    • 使用 event.stopPropogation() 方法將會(huì)沒用,因?yàn)槭录偸且呀?jīng)被委托到了document元素上
    • 因?yàn)樗械倪x擇器或者事件信息都被附加到document元素上了承边,所以 一旦有一個(gè)事件要調(diào)用某個(gè)事件處理函數(shù)遭殉,Jquery會(huì)在一大堆儲(chǔ)存的元數(shù)據(jù)中使用matchesSelector方法來決定哪一個(gè)事件處理函數(shù)將會(huì)被調(diào)用,如果這個(gè)函數(shù)有的話博助。
    • 因?yàn)槟闼B接的事件總是被委托到document上险污,所如果你的DOM的層級(jí)很深的話,這會(huì)導(dǎo)致一定的性能問題
  • Delegate
    .delegate()方法與live()方式實(shí)現(xiàn)方式相類似富岳,它不是將選擇器或者事件信息附加到document蛔糯,而是讓你指定附加的元素。就像是live()方法一樣窖式,這個(gè)方法使用事件委托來正確地工作蚁飒。
    如果你跳過了前面關(guān)于 .live() 方法的介紹,你可能要回去重新看看它萝喘,因?yàn)檫@里涉及到之前我所闡述的一些內(nèi)部邏輯

/* .delegate() 方法會(huì)將選擇器和事件信息 ( "li a" & "click" ) 附加到你指定的元素上 ( "#members" )淮逻。
*/
$( "#members" ).delegate( "li a", "click", function( e ) {} );

.delegate()方法十分強(qiáng)大。在上面這個(gè)例子中阁簸,與事件處理函數(shù)關(guān)聯(lián)的選擇器和事件信息將會(huì)被附加到( #members" )這個(gè)元素上爬早。這樣做比使用live()高效多了,因?yàn)閘ive()方法總是將與事件處理函數(shù)關(guān)聯(lián)的選擇器和事件信息附加到document元素上强窖。另外凸椿,使用.delegate()方法解決許多其他問題。請(qǐng)參閱下方列出的詳細(xì)信息翅溺。

  • 優(yōu)點(diǎn):

    • 你可以選擇將選擇器或者事件信息附加到指定的元素脑漫。
    • 匹配操作實(shí)際上在前面并沒有執(zhí)行髓抑,而是用來注冊(cè)到指定的元素。
    • 鏈?zhǔn)讲僮骺梢缘玫秸_的支持
    • Jquery仍然需要迭代這些選擇器或者事件信息來匹配元素优幸,不過因?yàn)槟憧梢赃x擇哪一個(gè)元素作為根元素吨拍,所以篩選的量會(huì)大幅減少
      因?yàn)檫@項(xiàng)技術(shù)使用了事件委托機(jī)制,它可以匹配到被動(dòng)態(tài)地添加到DOM的元素
    • 你可以在文檔加載完之前連接事件處理函數(shù)
  • 缺點(diǎn):

    • 從.bind()方法不可以直接升級(jí)到.delegate()方法
    • Jquery仍然需要使用marchesSelector方法在附加到指定根元素的選擇器或者事件信息中篩選決定哪一個(gè)事件處理函數(shù)會(huì)被調(diào)用网杆。然而羹饰,附加到指定根元素的元數(shù)據(jù)會(huì)比使用live()方法的時(shí)候要小得多。
      當(dāng)操作大量匹配的元素時(shí)會(huì)有性能方面的問題
    • 附加操作是在前期完成的,這可能導(dǎo)致頁面加載時(shí)存在性能問題
  • On
    你知道嗎碳却,在Jquery 1.7版本中.bind() 队秩, .live() 和.delegate()方法只需要使用.on()方法一種方式來調(diào)用它們。當(dāng)然.unbind() 昼浦, .die() 和.undelegate()方法也一樣馍资。一下代碼片段是從Jquery 1.7版本的源碼中截取出來的

bind: function( types, data, fn ) {
 return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
 return this.off( types, null, fn );
},
live: function( types, data, fn ) {
 jQuery( this.context ).on( types, this.selector, data, fn );
 return this;
},
die: function( types, fn ) {
 jQuery( this.context ).off( types, this.selector || "**", fn );
 return this;
},
delegate: function( selector, types, data, fn ) {
 return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
 return arguments.length == 1 ? 
  this.off( selector, "**" ) : 
  this.off( types, selector, fn );
}
//考慮到這一點(diǎn),使用.on()方法看起來像以下方式一樣...
 /* Jquery的 .bind() , .live() 和 .delegate() 方法只需要使用`.on()`方法一種方式來調(diào)用它們 */
 
// Bind
$( "#members li a" ).on( "click", function( e ) {} ); 
$( "#members li a" ).bind( "click", function( e ) {} );
 
// Live
$( document ).on( "click", "#members li a", function( e ) {} ); 
$( "#members li a" ).live( "click", function( e ) {} );
 
// Delegate
$( "#members" ).on( "click", "li a", function( e ) {} ); 
$( "#members" ).delegate( "li a", "click", function( e ) {} );

你可能注意到了关噪,我如何使用.on()方法決定了它如何調(diào)用其他方法鸟蟹。你可以認(rèn)為.on()方法被具有不同簽名的方法”重載“了,而這些方法實(shí)現(xiàn)了不同的事件綁定的連接方式使兔。 .on()方法的出現(xiàn)為API帶來了很多方面的一致性建钥,并希望讓事情變得不那么混亂。

  • 優(yōu)點(diǎn):
    • 使各種事件綁定方法一致虐沥。
    • 因?yàn)樵贘query源碼中.bind() 熊经, .live() 和.delegate()方法實(shí)際上是調(diào)用了此方法,因此簡(jiǎn)化了jQuery代碼庫并刪除了一級(jí)重定向置蜀。
    • 這種方式仍然提供了使用.delegate()方法的優(yōu)點(diǎn)奈搜,并且仍然提供對(duì).bind()方法的支持,如果你需要的話盯荤。
  • 缺點(diǎn):
    • 給人帶來了一些疑惑馋吗,因?yàn)榉椒ǖ膶?shí)際執(zhí)行方式將根據(jù)你如何調(diào)用方法而改變。
  • 總結(jié)
    使用.bind()方法非常浪費(fèi)性能因?yàn)樗淹粋€(gè)事件處理函數(shù)附加到了每一個(gè)匹配的元素上
    你應(yīng)該停止使用.live()方法因?yàn)樗粭売昧送瑫r(shí)也會(huì)帶來很多問題
    使用.delegate()方法會(huì)給你帶來很多好處當(dāng)你需要解決一些性能上的問題和對(duì)動(dòng)態(tài)添加的元素作出處理
    新的.on()方法其實(shí)就是模擬.bind() 秋秤, .live() 和.delegate()實(shí)現(xiàn)的語法糖宏粤,具體取決于你如何調(diào)用它
    新的方向是使用新的.on()方法。先熟悉語法灼卢,并開始在你的所有的Jquery 1.7版本以上的項(xiàng)目使用它吧绍哎!

狀態(tài)碼說明

  • 1**
    信息,服務(wù)器收到請(qǐng)求鞋真,需要請(qǐng)求者繼續(xù)執(zhí)行操作
  • 2**
    成功崇堰,操作被成功接收并處理
  • 3**
    重定向,需要進(jìn)一步的操作以完成請(qǐng)求
  • 4**
    客戶端錯(cuò)誤,請(qǐng)求包含語法錯(cuò)誤或無法完成請(qǐng)求
  • 5**
    服務(wù)器錯(cuò)誤海诲,服務(wù)器在處理請(qǐng)求的過程中發(fā)生了錯(cuò)誤
  • 100
    繼續(xù)
  • 101
    切換協(xié)議繁莹。服務(wù)器根據(jù)客戶端的請(qǐng)求切換協(xié)議。只能切換到更高級(jí)的協(xié)議特幔,例如咨演,切換到HTTP的新版本協(xié)議
  • 200
    OK 、請(qǐng)求成功蚯斯。一般用于GET與POST請(qǐng)求
  • 201
    已創(chuàng)建薄风。成功請(qǐng)求并創(chuàng)建了新的資源
  • 202
    已接受。已經(jīng)接受請(qǐng)求拍嵌,但未處理完成
  • 203
    非授權(quán)信息遭赂。請(qǐng)求成功。但返回的meta信息不在原始的服務(wù)器撰茎,而是一個(gè)副本
  • 204
    無內(nèi)容嵌牺。服務(wù)器成功處理打洼,但未返回內(nèi)容龄糊。在未更新網(wǎng)頁的情況下,可確保瀏覽器繼續(xù)顯示當(dāng)前文檔
  • 205
    重置內(nèi)容募疮。服務(wù)器處理成功炫惩,用戶終端(例如:瀏覽器)應(yīng)重置文檔視圖“⑴ǎ可通過此返回碼清除瀏覽器的表單域
  • 206
    部分內(nèi)容他嚷。服務(wù)器成功處理了部分GET請(qǐng)求
  • 300
    多種選擇。請(qǐng)求的資源可包括多個(gè)位置芭毙,相應(yīng)可返回一個(gè)資源特征與地址的列表用于用戶終端(例如:瀏覽器)選擇
  • 301
    永久移動(dòng)筋蓖。請(qǐng)求的資源已被永久的移動(dòng)到新URI,返回信息會(huì)包括新的URI退敦,瀏覽器會(huì)自動(dòng)定向到新URI粘咖。今后任何新的請(qǐng)求都應(yīng)使用新的URI代替
  • 302
    臨時(shí)移動(dòng)。與301類似侈百。但資源只是臨時(shí)被移動(dòng)瓮下。客戶端應(yīng)繼續(xù)使用原有URI
  • 303
    查看其它地址钝域。與301類似讽坏。使用GET和POST請(qǐng)求查看
  • 304
    未修改。所請(qǐng)求的資源未修改例证,服務(wù)器返回此狀態(tài)碼時(shí)路呜,不會(huì)返回任何資源。客戶端通常會(huì)緩存訪問過的資源胀葱,通過提供一個(gè)頭信息指出客戶端希望只返回在指定日期之后修改的資源
  • 305
    使用代理党涕。所請(qǐng)求的資源必須通過代理訪問
  • 306
    已經(jīng)被廢棄的HTTP狀態(tài)碼
  • 307
    臨時(shí)重定向。與302類似巡社。使用GET請(qǐng)求重定向
  • 400
    客戶端請(qǐng)求的語法錯(cuò)誤膛堤,服務(wù)器無法理解
  • 401
    請(qǐng)求要求用戶的身份認(rèn)證
  • 402
    保留,將來使用
  • 403
    服務(wù)器理解請(qǐng)求客戶端的請(qǐng)求晌该,但是拒絕執(zhí)行此請(qǐng)求
  • 404
    服務(wù)器無法根據(jù)客戶端的請(qǐng)求找到資源(網(wǎng)頁)肥荔。通過此代碼,網(wǎng)站設(shè)計(jì)人員可設(shè)置"您所請(qǐng)求的資源無法找到"的個(gè)性頁面
  • 405
    客戶端請(qǐng)求中的方法被禁止
  • 406
    服務(wù)器無法根據(jù)客戶端請(qǐng)求的內(nèi)容特性完成請(qǐng)求
  • 407
    請(qǐng)求要求代理的身份認(rèn)證朝群,與401類似燕耿,但請(qǐng)求者應(yīng)當(dāng)使用代理進(jìn)行授權(quán) |
  • 408
    服務(wù)器等待客戶端發(fā)送的請(qǐng)求時(shí)間過長(zhǎng),超時(shí)
  • 409
    服務(wù)器完成客戶端的 PUT 請(qǐng)求時(shí)可能返回此代碼姜胖,服務(wù)器處理請(qǐng)求時(shí)發(fā)生了沖突
  • 410
    客戶端請(qǐng)求的資源已經(jīng)不存在誉帅。410不同于404,如果資源以前有現(xiàn)在被永久刪除了可使用410代碼右莱,網(wǎng)站設(shè)計(jì)人員可通過301代碼指定資源的新位置
  • 411
    服務(wù)器無法處理客戶端發(fā)送的不帶Content-Length的請(qǐng)求信息
  • 412
    客戶端請(qǐng)求信息的先決條件錯(cuò)誤
  • 413
    由于請(qǐng)求的實(shí)體過大蚜锨,服務(wù)器無法處理,因此拒絕請(qǐng)求慢蜓。為防止客戶端的連續(xù)請(qǐng)求亚再,服務(wù)器可能會(huì)關(guān)閉連接。如果只是服務(wù)器暫時(shí)無法處理晨抡,則會(huì)包含一個(gè)Retry-After的響應(yīng)信息
  • 414
    請(qǐng)求的URI過長(zhǎng)(URI通常為網(wǎng)址)氛悬,服務(wù)器無法處理
  • 415
    服務(wù)器無法處理請(qǐng)求附帶的媒體格式
  • 416
    客戶端請(qǐng)求的范圍無效
  • 417
    服務(wù)器無法滿足Expect的請(qǐng)求頭信息
  • 500
    服務(wù)器內(nèi)部錯(cuò)誤,無法完成請(qǐng)求
  • 501
    服務(wù)器不支持請(qǐng)求的功能耘柱,無法完成請(qǐng)求
  • 502
    作為網(wǎng)關(guān)或者代理工作的服務(wù)器嘗試執(zhí)行請(qǐng)求時(shí)如捅,從遠(yuǎn)程服務(wù)器接收到了一個(gè)無效的響應(yīng)
  • 503
    由于超載或系統(tǒng)維護(hù),服務(wù)器暫時(shí)的無法處理客戶端的請(qǐng)求调煎。延時(shí)的長(zhǎng)度可包含在服務(wù)器的Retry-After頭信息中
  • 504
    充當(dāng)網(wǎng)關(guān)或代理的服務(wù)器镜遣,未及時(shí)從遠(yuǎn)端服務(wù)器獲取請(qǐng)求
  • 505
    服務(wù)器不支持請(qǐng)求的HTTP協(xié)議的版本,無法完成處理

promise汛蝙、generator烈涮、async/await怎么使用,有什么區(qū)別

  • 異步編程的方法有下面四種

    • 回調(diào)函數(shù)
    • 事件監(jiān)聽
    • 發(fā)布/訂閱
    • Promise對(duì)象
    • async/await
  • 回調(diào)函數(shù)
    所謂回調(diào)函數(shù)(callback)窖剑,就是把任務(wù)分成兩步完成坚洽,第二步單獨(dú)寫在一個(gè)函數(shù)里面,等到重新執(zhí)行這個(gè)任務(wù)時(shí)西土,就直接調(diào)用這個(gè)函數(shù)讶舰。

 // 例如Node.js中讀取文件
 fs.readFile('a,txt', (err,data) = >{
     if(err) throw err;
    console.log(data);
 })

上面代碼中readFile的第二個(gè)參數(shù)就是回調(diào)函數(shù),等到讀取完a.txt文件時(shí),這個(gè)函數(shù)才會(huì)執(zhí)行跳昼。

  • Promise
    使用回調(diào)函數(shù)本身沒有問題般甲,但有“回調(diào)地獄”的問題。
    假定我們有一個(gè)需求鹅颊,讀取完A文件之后讀取B文件敷存,再讀取C文件,代碼如下
 fs.readFile(fileA,  (err, data) => {
   fs.readFile(fileB,  (err, data) => {
      fs.readFile(fileC, (err,data)=>{
        //do something
     })
   });
 });
//這時(shí)候Promise出現(xiàn)了堪伍!它不是新的功能锚烦,而是一種新的寫法,用來解決“回調(diào)地獄”的問題帝雇。
/**
 * 傳入?yún)?shù) n涮俄,表示這個(gè)函數(shù)執(zhí)行的時(shí)間(毫秒)
 * 執(zhí)行的結(jié)果是 n + 200,這個(gè)值將用于下一步驟
 */
function A(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return A(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
      return A(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
     return A(n);
}

上面代碼中有4個(gè)函數(shù)尸闸,A()返回一個(gè)Promise對(duì)象彻亲,接收參數(shù)n,n秒后執(zhí)行resolve(n+200)吮廉。step1苞尝、 step2、step3對(duì)應(yīng)三個(gè)步驟
現(xiàn)在用Promise實(shí)現(xiàn)這三個(gè)步驟:

function doIt() {
    console.time('do it now')
    const time1 = 300;
    step1(time1)
          .then( time2 =>step2(time2))
          .then( time3 => step3(time3))
          .then( result => {
              console.log(`result is ${result}`)
           });
}
doIt();
// 輸出結(jié)果如下
step1 with 300
step2 with 500
step3 with 700
result is 900
result是step3()的參數(shù)700+200 = 900茧痕。

可見野来,Promise的寫法只是回調(diào)函數(shù)的改進(jìn),用then()方法免去了嵌套踪旷,更為直觀。
但這樣寫絕不是最好的豁辉,代碼變得十分冗余令野,一堆的then。
所以徽级,最優(yōu)秀的解決方案是什么呢气破?
開頭暴露了,就是async/await
講async前我們先講講協(xié)程與Generator

  • 協(xié)程
    協(xié)程(coroutine)餐抢,意思是多個(gè)線程相互協(xié)作现使,完成異步任務(wù)。
    它的運(yùn)行流程如下
    協(xié)程A開始執(zhí)行
    協(xié)程A執(zhí)行到一半旷痕,暫停執(zhí)行碳锈,執(zhí)行的權(quán)利轉(zhuǎn)交給協(xié)程B。
    一段時(shí)間后B交還執(zhí)行權(quán)
    協(xié)程A重得執(zhí)行權(quán)欺抗,繼續(xù)執(zhí)行
    上面的協(xié)程A就是一個(gè)異步任務(wù)售碳,因?yàn)樵趫?zhí)行過程中執(zhí)行權(quán)被B搶了,被迫分成兩步完成。
讀取文件的協(xié)程代碼如下:
function task() {
  // 其他代碼
   var f = yield readFile('a.txt')
   // 其他代碼
}

task()函數(shù)就是一個(gè)協(xié)程贸人,函數(shù)內(nèi)部有個(gè)新單詞yield间景,yield中文意思為退讓,
顧名思義艺智,它表示執(zhí)行到此處倘要,task協(xié)程該交出它的執(zhí)行權(quán)了。也可以把yield命令理解為異步兩個(gè)階段的分界線十拣。
協(xié)程遇到y(tǒng)ield命令就會(huì)暫停碗誉,把執(zhí)行權(quán)交給其他協(xié)程,等到執(zhí)行權(quán)返回繼續(xù)往后執(zhí)行父晶。最大的優(yōu)點(diǎn)就是代碼寫法和同步操作幾乎沒有差別哮缺,只是多了yield命令。
這也是異步編程追求的甲喝,讓它更像同步編程

  • Generator函數(shù)
    Generator是協(xié)程在ES6的實(shí)現(xiàn)尝苇,最大的特點(diǎn)就是可以交出函數(shù)的執(zhí)行權(quán),懂得退讓埠胖。
function* gen(x) {
    var y = yield x +2;
    return y;
  } 
  var g = gen(1);
  console.log( g.next()) // { value: 3, done: false }
  console.log( g.next()) // { value: undefined, done: true }

上面代碼中糠溜,函數(shù)多了*號(hào),用來表示這是一個(gè)Generator函數(shù)直撤,和普通函數(shù)不一樣非竿,不同之處在于執(zhí)行它不會(huì)返回結(jié)果,

返回的是指針對(duì)象g谋竖,這個(gè)指針g有個(gè)next方法红柱,調(diào)用它會(huì)執(zhí)行異步任務(wù)的第一步。
對(duì)象中有兩個(gè)值蓖乘,value和done锤悄,value 屬性是 yield 語句后面表達(dá)式的值,表示當(dāng)前階段的值嘉抒,done表示是否Generator函數(shù)是否執(zhí)行完畢零聚。

下面看看Generator函數(shù)如何執(zhí)行一個(gè)真實(shí)的異步任務(wù)

var fetch = require('node-fetch');
function gen(){
  var url = 'https://api.github.com/users/github';
  var result = yield fetch(url);
  console.log(result.bio);
}

var g = gen();
var result = g.next();
result.value.then( data => return data.json)
                  .then (data => g.next(data))

上面代碼中,首先執(zhí)行Generator函數(shù)些侍,得到對(duì)象g隶症,調(diào)用next方法,此時(shí)
result ={ value: Promise { <pending> }, done: false }
因?yàn)閒etch返回的是一個(gè)Promise對(duì)象岗宣,(即value是一個(gè)Promise對(duì)象)所以要用then才能調(diào)用下一個(gè)next方法蚂会。

雖然Generator將異步操作表示得很簡(jiǎn)潔,但是管理麻煩狈定,何時(shí)執(zhí)行第一階段颂龙,又何時(shí)執(zhí)行第二階段习蓬?
是的,這時(shí)候到Async/await出現(xiàn)了措嵌!

  • Async/await

從回調(diào)函數(shù)躲叼,到Promise對(duì)象,再到Generator函數(shù)企巢,JavaScript異步編程解決方案歷程可謂辛酸枫慷,終于到了Async/await。很多人認(rèn)為它是異步操作的最終解決方案(謝天謝地浪规,這下不用再學(xué)新的解決方案了吧)

其實(shí)async函數(shù)就是Generator函數(shù)的語法糖或听,例如下面兩個(gè)代碼:

var gen = function* (){
  var f1 = yield readFile('./a.txt');
  var f2 = yield readFile('./b.txt');
  console.log(f1.toString());
  console.log(f2.toString());
};
var asyncReadFile = async function (){
  var f1 = await  readFile('./a.txt');
  var f2 = await  readFile('./b.txt');
  console.log(f1.toString());
  console.log(f2.toString());
};

上面的為Generator函數(shù)讀取兩個(gè)文件,下面為async/await讀取笋婿,比較可發(fā)現(xiàn)誉裆,兩個(gè)函數(shù)其實(shí)是一樣的,async不過是把Generator函數(shù)的*號(hào)換成async缸濒,yield換成await足丢。

1.async函數(shù)用法

上面說了async不過是Generator函數(shù)的語法糖,那為什么要取這個(gè)名字呢庇配?自然是有理由的斩跌。
async是“異步”,而await是async wait的簡(jiǎn)寫捞慌,即異步等待耀鸦。所以應(yīng)該很好理解async用于聲明一個(gè)function是異步的,await用于等待一個(gè)異步方法執(zhí)行完成

下面來看一個(gè)例子理解async命令的作用

async function test() {
  return "async 有什么用啸澡?";
}
const result = test();
console.log(result) 
輸出:
Promise { 'async 有什么用袖订?' }

可以看到,輸出的是一個(gè)Promise對(duì)象锻霎!
所以著角,async函數(shù)返回的是一個(gè)Promise對(duì)象,如果直接return 一個(gè)直接量旋恼,async會(huì)把這個(gè)直接量通過PromIse.resolve()封裝成Promise對(duì)象

注意點(diǎn)
一般來說,都認(rèn)為await是在等待一個(gè)async函數(shù)完成奄容,確切的說等待的是一個(gè)表示式冰更,這個(gè)表達(dá)式的計(jì)算結(jié)果是Promise對(duì)象或者是其他值(沒有限定是什么)

即await后面不僅可以接Promise,還可以接普通函數(shù)或者直接量昂勒。

同時(shí)蜀细,我們可以把a(bǔ)sync理解為一個(gè)運(yùn)算符,用于組成表達(dá)式戈盈,表達(dá)式的結(jié)果取決于它等到的東西

等到非Promise對(duì)象 表達(dá)式結(jié)果為它等到的東西
等到Promise對(duì)象 await就會(huì)阻塞后面的代碼奠衔,等待Promise對(duì)象resolve谆刨,取得resolve的值,作為表達(dá)式的結(jié)果
還是那個(gè)業(yè)務(wù)归斤,分多個(gè)步驟完成,每個(gè)步驟依賴于上一個(gè)步驟的結(jié)果,用setTimeout模擬異步操作液南。

/**
 * 傳入?yún)?shù) n球切,表示這個(gè)函數(shù)執(zhí)行的時(shí)間(毫秒)
 * 執(zhí)行的結(jié)果是 n + 200,這個(gè)值將用于下一步驟
 */
function takeLongTime(n) {
    return new Promise(resolve => {
        setTimeout(() => resolve(n + 200), n);
    });
}

function step1(n) {
    console.log(`step1 with ${n}`);
    return takeLongTime(n);
}

function step2(n) {
    console.log(`step2 with ${n}`);
    return takeLongTime(n);
}

function step3(n) {
    console.log(`step3 with ${n}`);
    return takeLongTime(n);
}
async實(shí)現(xiàn)方法

async function doIt() {
    console.time("doIt");
    const time1 = 300;
    const time2 = await step1(time1);
    const time3 = await step2(time2);
    const result = await step3(time3);
    console.log(`result is ${result}`);
    console.timeEnd("doIt");
}

doIt();
輸出結(jié)果和上面用Promise實(shí)現(xiàn)是一樣的迫横,但這個(gè)代碼結(jié)構(gòu)看起來清晰得多番舆,幾乎跟同步寫法一樣。
  1. async函數(shù)的優(yōu)點(diǎn)

(1)內(nèi)置執(zhí)行器
Generator 函數(shù)的執(zhí)行必須靠執(zhí)行器矾踱,所以才有了 co 函數(shù)庫恨狈,而 async 函數(shù)自帶執(zhí)行器。也就是說呛讲,async 函數(shù)的執(zhí)行禾怠,與普通函數(shù)一模一樣,只要一行圣蝎。

(2) 語義化更好
async 和 await刃宵,比起星號(hào)和 yield,語義更清楚了徘公。async 是“異步”的簡(jiǎn)寫牲证,而 await 可以認(rèn)為是 async wait 的簡(jiǎn)寫。所以應(yīng)該很好理解 async 用于申明一個(gè) function 是異步的关面,而 await 用于等待一個(gè)異步方法執(zhí)行完成坦袍。

(3)更廣的適用性
yield 命令后面只能是 Thunk 函數(shù)或 Promise 對(duì)象,而 async 函數(shù)的 await 命令后面等太,可以跟 Promise 對(duì)象和原始類型的值(數(shù)值捂齐、字符串和布爾值,但這時(shí)等同于同步操作

js中的繼承?

  • 原型鏈繼承 JavaScript實(shí)現(xiàn)繼承的基本思想:通過原型將一個(gè)引用類型繼承另一個(gè)引用類型的屬性和方法缩抡。
  • 借用構(gòu)造函數(shù)繼承(偽造對(duì)象或經(jīng)典繼承) JavaScript實(shí)現(xiàn)繼承的基本思想:在子類構(gòu)造函數(shù)內(nèi)部調(diào)用超類型構(gòu)造函數(shù)奠宜。 通過使用apply()和call()方法可以在新創(chuàng)建的子類對(duì)象上執(zhí)行構(gòu)造函數(shù)。
  • 組合繼承(原型+借用構(gòu)造)(偽經(jīng)典繼承) JavaScript實(shí)現(xiàn)繼承的基本思想:將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合在一塊瞻想,從而發(fā)揮兩者之長(zhǎng)的一種繼承模式压真。
  • 將原型鏈和借用構(gòu)造函數(shù)的技術(shù)組合到一起,從而取長(zhǎng)補(bǔ)短發(fā)揮兩者長(zhǎng)處的一種繼承模式蘑险。
  • 原型式繼承 JavaScript實(shí)現(xiàn)繼承的基本思想:借助原型可以基于已有的對(duì)象創(chuàng)建新對(duì)象滴肿,同時(shí)還不必須因此創(chuàng)建自定義的類型。
  • 寄生式繼承 JavaScript實(shí)現(xiàn)繼承的基本思想:創(chuàng)建一個(gè)僅用于封裝繼承過程的函數(shù)佃迄,該函數(shù)在內(nèi)部以某種方式來增強(qiáng)對(duì)象泼差,最后再像真正是它做了所有工作一樣返回對(duì)象贵少。
  • 寄生式繼承是原型式繼承的加強(qiáng)版。
  • 寄生組合式繼承 JavaScript實(shí)現(xiàn)繼承的基本思想:通過借用函數(shù)來繼承屬性堆缘,通過原型鏈的混成形式來繼承方法滔灶。

常用的js數(shù)組操作方法有哪些?

  • Array.shift()
    刪除并返回第一個(gè)元素 作用:從數(shù)組中刪除第一個(gè)元素(即下標(biāo)為0的元素)套啤,并返回該元素宽气。
    注意:
    1、刪除元素之后潜沦,數(shù)組的長(zhǎng)度-1萄涯。
    2、如果數(shù)組是空的唆鸡,那么 shift() 方法將不進(jìn)行任何操作涝影,返回 undefined 值。

  • Array.pop()
    刪除并返回最后一個(gè)元素 作用:從數(shù)組中刪除最后一個(gè)元素(即下標(biāo)為length-1的元素)争占,并返回該元素燃逻。
    注意:
    1、刪除元素之后臂痕,數(shù)組的長(zhǎng)度-1伯襟。
    2、如果數(shù)組是空的握童,那么 shift() 方法將不進(jìn)行任何操作姆怪,返回 undefined 值。

  • Array.push(param1[,param2,...paramN])
    尾部添加元素 作用:在數(shù)組的尾部添加一個(gè)元素澡绩,并返回新數(shù)組的長(zhǎng)度稽揭。
    注意
    1、它是直接修改該數(shù)組肥卡,而不是重新創(chuàng)建一個(gè)數(shù)組溪掀。
    2、它和pop是一對(duì)相反的先進(jìn)后出的棧功能方法步鉴。
    3揪胃、它可以同時(shí)給一個(gè)數(shù)組添加多個(gè)元素。

  • Array.unshift(newElement1[,newElement2,...newElementN]
    頭部添加元素 作用:在數(shù)組的頭部添加一個(gè)或多個(gè)元素氛琢,并返回新數(shù)組的長(zhǎng)度只嚣。
    注意:
    1、它是直接修改該數(shù)組艺沼,而不是重新創(chuàng)建一個(gè)數(shù)組。
    2蕴掏、IE瀏覽器不支持該方法障般。

  • Array.join([separator])
    轉(zhuǎn)換成字符串 作用:把數(shù)組的所有元素放入到一個(gè)字符串中调鲸。
    注意:
    1、參數(shù)separator表示字符串中元素的分隔符挽荡,可以為空藐石,默認(rèn)為半角逗號(hào)。
    2定拟、該方法并不修改數(shù)組于微。

  • Array.contact(array1[,array2,...arrayN])
    連接數(shù)組 作用:將兩個(gè)或兩個(gè)以上的數(shù)組連接成一個(gè)數(shù)組,并返回連接后的數(shù)組青自。
    注意:
    1株依、該方法并不會(huì)改變現(xiàn)有的數(shù)組,而是返回被連接的多個(gè)數(shù)組的一個(gè)副本延窜。
    2恋腕、如果多個(gè)數(shù)組里有值相同的元素,那也不會(huì)重復(fù)出現(xiàn)逆瑞,而不會(huì)把重復(fù)的元素過濾掉荠藤。

  • Array.reverse()
    反轉(zhuǎn)數(shù)組 作用:把數(shù)組的所有元素順序反轉(zhuǎn)。
    注意:
    1获高、該方法會(huì)直接修改數(shù)組哈肖,而不會(huì)創(chuàng)建新的數(shù)組。

  • Array.slice(start[, end])
    截取數(shù)組 作用:截取數(shù)組中指定位置的元素念秧,并返回一個(gè)新的子數(shù)組淤井。
    注意:
    1、該方法并不會(huì)改變現(xiàn)有的數(shù)組出爹,而是原數(shù)組的一個(gè)子數(shù)組庄吼。
    2、參數(shù)start是必選严就,表示開始下標(biāo)总寻,如果start為負(fù)數(shù),表示從末尾開始梢为,-1表示最后一個(gè)元素渐行,依次類推。
    3铸董、end是可選表示結(jié)束下標(biāo)祟印,如果沒有指定,表示到結(jié)尾元素粟害。

  • Array.splice()
    刪除指定元素 作用:從數(shù)組指定位置刪除指定數(shù)量的元素蕴忆,并返回被刪除的元素。
    注意:
    1悲幅、該方法會(huì)直接修改數(shù)組套鹅。
    2站蝠、splice() 方法與 slice() 方法的作用是不同的,splice() 方法會(huì)直接對(duì)數(shù)組進(jìn)行修改卓鹿,而slice只是截取原數(shù)組的一部分后返回一個(gè)子數(shù)組菱魔,并不會(huì)修改原數(shù)組。

  • Array.toString()
    轉(zhuǎn)換成字符串 作用:數(shù)組轉(zhuǎn)換為字符串吟孙,并返回該字符串澜倦。
    注意:
    1、該方法和不帶參數(shù)的join()方法效果一樣杰妓。

js數(shù)組去重

  • 使用es6 set方法 [...new Set(arr)]

      let arr = [1,2,3,4,3,2,3,4,6,7,6]; 
      let unique = (arr)=> [...new Set(arr)]; 
      unique(arr); //[1, 2, 3, 4, 6, 7]
    
  • 利用新數(shù)組indexOf查找 indexOf() 方法可返回某個(gè)指定的元素在數(shù)組中首次出現(xiàn)的位置藻治。如果沒有就返回-1。

  • for 雙重循環(huán) 通過判斷第二層循環(huán)稚失,去重的數(shù)組中是否含有該元素栋艳,如果有就退出第二層循環(huán),如果沒有j==result.length就相等句各,然后把對(duì)應(yīng)的元素添加到最后的數(shù)組里面吸占。

     let arr = [1,2,3,4,3,2,3,4,6,7,6];
     let result = []; 
     for(var i = 0 ; i< arr.length; i++) {
        for(var j = 0 ; j < result.length ; j++) {
           if( arr[i] === result[j]){  
               break;
          };
       };
      if(j == result.length){
              result.push(arr[i]);
         };
      };
     console.log(result);
    
  • 利用for嵌套for,然后splice去重

    functionunique(arr){ 
       for(vari=0; i<arr.length; i++){
         for(varj=i+1; j<arr.length; j++){
            if(arr[i]==arr[j]){
             //第一個(gè)等同于第二個(gè)凿宾,splice方法刪除第二個(gè) 
            arr.splice(j,1);
            j--; 
            } 
          }
        }
       returnarr; 
     }
    
  • 利用filter

    let arr = [1,2,3,4,3,2,3,4,6,7,6]; 
    let unique = (arr) => { 
        return arr.filter((item,index) => {
             return arr.indexOf(item) === index;
      }) }; 
    unique(arr);
    
    let arr = [1,2,3,4,3,2,3,4,6,7,6]; let unique = (arr) => {
     return arr.filter((item,index) => {
       return arr.indexOf(item) === index;
      }) 
    };
    unique(arr);
    
  • 利用Map數(shù)據(jù)結(jié)構(gòu)去重

      let arr = [1,2,3,4,3,2,3,4,6,7,6]; 
      let unique = (arr)=> {
          let seen = new Map();
          return arr.filter((item) => {
              return !seen.has(item) && seen.set(item,1);
           }); 
         };
        unique(arr);
    

數(shù)組中的forEach和map的區(qū)別矾屯?

  • 相同點(diǎn)
    • 都是循環(huán)遍歷數(shù)組中的每一項(xiàng)
    • forEach和map方法里每次執(zhí)行匿名函數(shù)都支持3個(gè)參數(shù),參數(shù)分別是item(當(dāng)前每一項(xiàng))初厚,index(索引值)件蚕,arr(原數(shù)組)
    • 匿名函數(shù)中的this都是指向window 只能遍歷數(shù)組 都不會(huì)改變?cè)瓟?shù)組
  • 區(qū)別
    • map方法返回一個(gè)新的數(shù)組,數(shù)組中的元素為原始數(shù)組調(diào)用函數(shù)處理后的值产禾。
    • map方法不會(huì)對(duì)空數(shù)組進(jìn)行檢測(cè)排作,map方法不會(huì)改變?cè)紨?shù)組。
    • 瀏覽器支持:chrome亚情、Safari1.5+妄痪、opera都支持,IE9+, 若arr為空數(shù)組楞件,則map方法返回的也是一個(gè)空數(shù)組衫生。
    • forEach方法用來調(diào)用數(shù)組的每個(gè)元素,將元素傳給回調(diào)函數(shù)
    • forEach對(duì)于空數(shù)組是不會(huì)調(diào)用回調(diào)函數(shù)的土浸。 無論arr是不是空數(shù)組罪针,forEach返回的都是undefined。這個(gè)方法只是將數(shù)組中的每一項(xiàng)作為callback的參數(shù)執(zhí)行一次黄伊。

js事件循環(huán) event loop泪酱?

  • 主線程從"任務(wù)隊(duì)列"中讀取事件,這個(gè)過程是循環(huán)不斷的,所以整個(gè)的這種運(yùn)行機(jī)制又稱為Event Loop(事件循環(huán))西篓。

Math.min()和Math.max()大小比較愈腾?

  • Math.max() Math.min() Math.min()如果沒有參數(shù),則返回 Infinity岂津。
  • Infinity 是javascript 中全局對(duì)象的一個(gè)屬性,在瀏覽器環(huán)境中就是 window 對(duì)象的一個(gè)屬性悦即,表示無窮大吮成。
  • Math.max()沒有傳遞參數(shù)時(shí)返回的是 -Infinity。 因此 Math.min() 要比 Math.max() 大辜梳。

怎么實(shí)現(xiàn)對(duì)象的深淺拷貝粱甫?

  • 淺拷貝很容易,只需要使用賦值運(yùn)算符(=)即可

文件上傳如何做斷點(diǎn)續(xù)傳?

  • 文件斷點(diǎn)續(xù)傳是HTML5引入的新特性作瞄,HTML5的FILE api茶宵,有一個(gè)slice方法,可以將BLOB對(duì)象進(jìn)行分割宗挥。前端通過FileList對(duì)象獲取到相應(yīng)的文件乌庶,按照指定的分割方式將大文件分段,然后一段一段地傳給后端契耿,后端再按順序一段段將文件進(jìn)行拼接瞒大。
  • 斷點(diǎn)續(xù)傳原理,目前比較常用的斷點(diǎn)續(xù)傳的方法有兩種搪桂,
    • 一種是通過websocket接口進(jìn)行文件上傳透敌,
    • 另一種是通過ajax,兩種方法各有千秋踢械,雖然websocket聽起來比較高端些酗电,但是除了用了不同的協(xié)議外其他的算法基本上都是很相似的,并且服務(wù)端要開啟ws接口内列,這里用相對(duì)方便的ajax來說明斷點(diǎn)上傳的思路撵术。
    • 首先是文件的識(shí)別,一個(gè)文件被分成了若干份之后如何告訴服務(wù)器你切了多少塊德绿,以及最終服務(wù)器應(yīng)該如何把你上傳上去的文件進(jìn)行合并荷荤?
    • 因此在文件開始上傳之前,我們和服務(wù)器要有一個(gè)“握手”的過程移稳,告訴服務(wù)器文件信息蕴纳,然后和服務(wù)器約定切片的大小,當(dāng)和服務(wù)器達(dá)成共識(shí)之后就可以開始后續(xù)的文件傳輸了个粱。
    • 前臺(tái)要把每一塊的文件傳給后臺(tái)古毛,成功之后前端和后端都要標(biāo)識(shí)一下,以便后續(xù)的斷點(diǎn)。
    • 當(dāng)文件傳輸中斷之后用戶再次選擇文件就可以通過標(biāo)識(shí)來判斷文件是否已經(jīng)上傳了一部分稻薇,如果是的話嫂冻,那么我們可以接著上次的進(jìn)度繼續(xù)傳文件,以達(dá)到續(xù)傳的功能塞椎。

js如何處理防抖和節(jié)流桨仿?

  • 在進(jìn)行窗口的resize、scroll案狠,輸入框內(nèi)容校驗(yàn)等操作時(shí)服傍,如果事件處理函數(shù)調(diào)用的頻率無限制,會(huì)加重瀏覽器的負(fù)擔(dān)骂铁,導(dǎo)致用戶體驗(yàn)非常糟糕吹零。
  • 此時(shí)我們可以采用debounce(防抖)和throttle(節(jié)流)的方式來減少調(diào)用頻率,同時(shí)又不影響實(shí)際效果拉庵。 函數(shù)防抖
  • 函數(shù)防抖(debounce):當(dāng)持續(xù)觸發(fā)事件時(shí)灿椅,一定時(shí)間段內(nèi)沒有再觸發(fā)事件,事件處理函數(shù)才會(huì)執(zhí)行一次钞支,如果設(shè)定的時(shí)間到來之前茫蛹,又一次觸發(fā)了事件,就重新開始延時(shí)伸辟。
  • 如下麻惶,持續(xù)觸發(fā)scroll事件時(shí),并不執(zhí)行handle函數(shù)信夫,當(dāng)1000毫秒內(nèi)沒有觸發(fā)scroll事件時(shí)窃蹋,才會(huì)延時(shí)觸發(fā)scroll事件。
  function debounce(fn, wait) {
  var timeout = null;   
  return function() {       
     if(timeout !== null) 
        clearTimeout(timeout);       
       timeout = setTimeout(fn, wait);   
     }
   } 
  // 處理函數(shù) function handle() {   
 console.log(Math.random()); } // 滾動(dòng)事件  
 window.addEventListener('scroll', debounce(handle, 1000));
 // 函數(shù)節(jié)流
  • 函數(shù)節(jié)流(throttle):當(dāng)持續(xù)觸發(fā)事件時(shí)静稻,保證一定時(shí)間段內(nèi)只調(diào)用一次事件處理函數(shù)警没。
  • 節(jié)流通俗解釋就比如我們水龍頭放水,閥門一打開振湾,水嘩嘩的往下流杀迹,秉著勤儉節(jié)約的優(yōu)良傳統(tǒng)美德,我們要把水龍頭關(guān)小點(diǎn)押搪,最好是如我們心意按照一定規(guī)律在某個(gè)時(shí)間間隔內(nèi)一滴一滴的往下滴树酪。
  • 如下,持續(xù)觸發(fā)scroll事件時(shí)大州,并不立即執(zhí)行handle函數(shù)续语,每隔1000毫秒才會(huì)執(zhí)行一次handle函數(shù)。
   var throttle = function(func, delay) {
          var prev = Date.now();           
          return function() {               
               var context = this;               
               var args = arguments;               
               var now = Date.now();               
              if (now - prev >= delay) {                   
                 func.apply(context, args);                   
                 prev = Date.now();               
            }           
        }        
     }  
     function handle() {           
       console.log(Math.random());  
      }        
     window.addEventListener('scroll', throttle(handle, 1000)); 
    //總結(jié)
  • 函數(shù)防抖:將幾次操作合并為一此操作進(jìn)行厦画。原理是維護(hù)一個(gè)計(jì)時(shí)器疮茄,規(guī)定在delay時(shí)間后觸發(fā)函數(shù)滥朱,但是在delay時(shí)間內(nèi)再次觸發(fā)的話,就會(huì)取消之前的計(jì)時(shí)器而重新設(shè)置力试。這樣一來徙邻,只有最后一次操作能被觸發(fā)。
  • 函數(shù)節(jié)流:使得一定時(shí)間內(nèi)只觸發(fā)一次函數(shù)畸裳。原理是通過判斷是否到達(dá)一定時(shí)間來觸發(fā)函數(shù)缰犁。 區(qū)別:
  • 函數(shù)節(jié)流不管事件觸發(fā)有多頻繁,都會(huì)保證在規(guī)定時(shí)間內(nèi)一定會(huì)執(zhí)行一次真正的事件處理函數(shù)躯畴,而函數(shù)防抖只是在最后一次事件后才觸發(fā)一次函數(shù)民鼓。比如在頁面的無限加載場(chǎng)景下,我們需要用戶在滾動(dòng)頁面時(shí)蓬抄,每隔一段時(shí)間發(fā)一次
  • Ajax 請(qǐng)求,而不是在用戶停下滾動(dòng)頁面操作時(shí)才去請(qǐng)求數(shù)據(jù)夯到。這樣的場(chǎng)景嚷缭,就適合用節(jié)流技術(shù)來實(shí)現(xiàn)。

事件委托以及優(yōu)缺點(diǎn)?

  • 優(yōu)點(diǎn):
    • 減少事件注冊(cè)耍贾,節(jié)省內(nèi)存阅爽。比如,
    • 在table上代理所有td的click事件荐开。
    • 在ul上代理所有l(wèi)i的click事件付翁。
    • 簡(jiǎn)化了dom節(jié)點(diǎn)更新時(shí),相應(yīng)事件的更新晃听。比如
    • 不用在新添加的li上綁定click事件百侧。
    • 當(dāng)刪除某個(gè)li時(shí),不用移解綁上面的click事件能扒。 缺點(diǎn):
    • 事件委托基于冒泡佣渴,對(duì)于不冒泡的事件不支持。
    • 層級(jí)過多初斑,冒泡過程中辛润,可能會(huì)被某層阻止掉。
    • 理論上委托會(huì)導(dǎo)致瀏覽器頻繁調(diào)用處理函數(shù)见秤,雖然很可能不需要處理砂竖。所以建議就近委托,比如在table上代理td鹃答,而不是在document上代理td乎澄。
    • 把所有事件都用代理就可能會(huì)出現(xiàn)事件誤判。比如挣跋,在document中代理了所有button的click事件三圆,另外的人在引用改js時(shí),可能不知道,造成單擊button觸發(fā)了兩個(gè)click事件舟肉。

介紹this各種情況?

  • this的情況:
    • 以函數(shù)形式調(diào)用時(shí)修噪,this永遠(yuǎn)都是window
    • 以方法的形式調(diào)用時(shí),this是調(diào)用方法的對(duì)象
    • 以構(gòu)造函數(shù)的形式調(diào)用時(shí)路媚,this是新創(chuàng)建的那個(gè)對(duì)象
    • 使用call和apply調(diào)用時(shí)黄琼,this是指定的那個(gè)對(duì)象
    • 箭頭函數(shù):箭頭函數(shù)的this看外層是否有函數(shù)
    • 如果有,外層函數(shù)的this就是內(nèi)部箭頭函數(shù)的this
    • 如果沒有整慎,就是window
    • 特殊情況:通常意義上this指針指向?yàn)樽詈笳{(diào)用它的對(duì)象脏款。這里需要注意的一點(diǎn)就是如果返回值是一個(gè)對(duì)象,那么this指向的就是那個(gè)返回的對(duì)象裤园,如果返回值不是一個(gè)對(duì)象那么this還是指向函數(shù)的實(shí)例

== 和 ===的區(qū)別撤师,什么情況下用相等==?

  • ==
    運(yùn)算符稱作相等,用來檢測(cè)兩個(gè)操作數(shù)是否相等拧揽,這里的相等定義的非常寬松剃盾,可以允許進(jìn)行類型轉(zhuǎn)換
  • ===
    用來檢測(cè)兩個(gè)操作數(shù)是否嚴(yán)格相等
    • 對(duì)于string,number等基礎(chǔ)類型,==和===是有區(qū)別的 不同類型間比較淤袜,==之比較“轉(zhuǎn)化成同一類型后的值”看“值”是否相等痒谴,===如果類型不同,其結(jié)果就是不等
    • 同類型比較铡羡,直接進(jìn)行“值”比較积蔚,兩者結(jié)果一樣
    • 對(duì)于Array,Object等高級(jí)類型,==和===是沒有區(qū)別的
    • 基礎(chǔ)類型與高級(jí)類型烦周,==和===是有區(qū)別的 對(duì)于==尽爆,將高級(jí)轉(zhuǎn)化為基礎(chǔ)類型,進(jìn)行“值”比較论矾,因?yàn)轭愋筒煌?==結(jié)果為false

介紹下原型鏈(解決的是繼承問題嗎)

  • JavaScript原型: 每個(gè)對(duì)象都會(huì)在其內(nèi)部初始化一個(gè)屬性教翩,就是prototype(原型)。 原型鏈:
  • 當(dāng)我們?cè)L問一個(gè)對(duì)象的屬性時(shí)贪壳,如果這個(gè)對(duì)象內(nèi)部不存在這個(gè)屬性饱亿,那么他就會(huì)去prototype里找這個(gè)屬性,這個(gè)prototype又會(huì)有自己的prototype闰靴,于是就這樣一直找下去彪笼,也就是我們平時(shí)所說的原型鏈的概念。
  • 特點(diǎn):
    • JavaScript對(duì)象是通過引用來傳遞的蚂且,我們創(chuàng)建的每個(gè)新對(duì)象實(shí)體中并沒有一份屬于自己的原型副本配猫。當(dāng)我們修改原型時(shí),與之相關(guān)的對(duì)象也會(huì)繼承這一改變杏死。

JS里垃圾回收機(jī)制是什么泵肄,常用的是哪種捆交,怎么處理的?

  • JS的垃圾回收機(jī)制是為了以防內(nèi)存泄漏腐巢,內(nèi)存泄漏的含義就是當(dāng)已經(jīng)不需要某塊內(nèi)存時(shí)這塊內(nèi)存還存在著品追,垃圾回收機(jī)制就是間歇的不定期的尋找到不再使用的變量,并釋放掉它們所指向的內(nèi)存冯丙。

  • JS中最常見的垃圾回收方式是標(biāo)記清除肉瓦。

  • 工作原理:是當(dāng)變量進(jìn)入環(huán)境時(shí),將這個(gè)變量標(biāo)記為“進(jìn)入環(huán)境”胃惜。當(dāng)變量離開環(huán)境時(shí)泞莉,則將其標(biāo)記為“離開環(huán)境”。標(biāo)記“離開環(huán)境”的就回收內(nèi)存船殉。

  • 工作流程

    • 垃圾回收器鲫趁,在運(yùn)行的時(shí)候會(huì)給存儲(chǔ)在內(nèi)存中的所有變量都加上標(biāo)記。
    • 去掉環(huán)境中的變量以及被環(huán)境中的變量引用的變量的標(biāo)記利虫。
    • 再被加上標(biāo)記的會(huì)被視為準(zhǔn)備刪除的變量饮寞。
    • 垃圾回收器完成內(nèi)存清除工作,銷毀那些帶標(biāo)記的值并回收他們所占用的內(nèi)存空間列吼。

27.Promise和setTimeout的區(qū)別?

  • 回顧JavaScript事件循環(huán)并發(fā)模型苦始,我們了解了setTimeout和Promise調(diào)用的都是異步任務(wù)寞钥,這一點(diǎn)是它們共同之處,也即都是通過任務(wù)隊(duì)列進(jìn)行管理/調(diào)度陌选。那么它們有什么區(qū)別嗎理郑?
  • 任務(wù)隊(duì)列
    • 前文已經(jīng)介紹了任務(wù)隊(duì)列的基礎(chǔ)內(nèi)容和機(jī)制,可選擇查看咨油,本文對(duì)任務(wù)隊(duì)列進(jìn)行拓展介紹您炉。JavaScript通過任務(wù)隊(duì)列管理所有異步任務(wù),而任務(wù)隊(duì)列還可以細(xì)分為MacroTask
    • Queue和MicoTask Queue兩類役电。 MacroTask Queue MacroTask
    • Queue(宏任務(wù)隊(duì)列)主要包括setTimeout,setInterval, setImmediate,
    • requestAnimationFrame, NodeJS中的`I/O等赚爵。 MicroTask Queue MicroTask
    • Queue(微任務(wù)隊(duì)列)主要包括兩類: 獨(dú)立回調(diào)microTask:如Promise,其成功/失敗回調(diào)函數(shù)相互獨(dú)立法瑟;
    • 復(fù)合回調(diào)microTask:如 Object.observe, MutationObserver 和NodeJs中的
    • process.nextTick 冀膝,不同狀態(tài)回調(diào)在同一函數(shù)體; MacroTask和MicroTask
    • JavaScript將異步任務(wù)分為MacroTask和MicroTask霎挟,那么它們區(qū)別何在呢窝剖? 依次執(zhí)行同步代碼直至執(zhí)行完畢;
    • 檢查MacroTask 隊(duì)列酥夭,若有觸發(fā)的異步任務(wù)赐纱,則取第一個(gè)并調(diào)用其事件處理函數(shù)脊奋,然后跳至第三步,若沒有需處理的異步任務(wù)疙描,則直接跳至第三步诚隙;
    • 檢查MicroTask隊(duì)列,然后執(zhí)行所有已觸發(fā)的異步任務(wù)淫痰,依次執(zhí)行事件處理函數(shù)最楷,直至執(zhí)行完畢,然后跳至第二步待错,若沒有需處理的異步任務(wù)中籽孙,則直接返回第二步,依次執(zhí)行后續(xù)步驟火俄;
    • 最后返回第二步犯建,繼續(xù)檢查MacroTask隊(duì)列,依次執(zhí)行后續(xù)步驟瓜客; 如此往復(fù)适瓦,若所有異步任務(wù)處理完成,則結(jié)束谱仪;

介紹下廣度優(yōu)先遍歷(BFS)和深度優(yōu)先遍歷(DFS)玻熙?

2446271091-5d883e2fa85e8_articlex.png
  • 廣度優(yōu)先遍歷 英文縮寫為BFS即Breadth FirstSearch。其過程檢驗(yàn)來說是對(duì)每一層節(jié)點(diǎn)依次訪問疯攒,訪問完一層進(jìn)入下一層斯入,而且每個(gè)節(jié)點(diǎn)只能訪問一次玄坦。對(duì)于上面的例子來說籽御,廣度優(yōu)先遍歷的

  • 結(jié)果是:A,B,C,D,E,F,G,H,I(假設(shè)每層節(jié)點(diǎn)從左到右訪問)留搔。 先往隊(duì)列中插入左節(jié)點(diǎn),再插右節(jié)點(diǎn)砂吞,這樣出隊(duì)就是先左節(jié)點(diǎn)后右節(jié)點(diǎn)了署恍。

  • 廣度優(yōu)先遍歷樹,需要用到隊(duì)列(Queue)來存儲(chǔ)節(jié)點(diǎn)對(duì)象,隊(duì)列的特點(diǎn)就是先進(jìn)先出蜻直。例如盯质,上面這顆樹的訪問如下:

  • 首先將A節(jié)點(diǎn)插入隊(duì)列中,隊(duì)列中有元素(A);

  • 將A節(jié)點(diǎn)彈出袭蝗,同時(shí)將A節(jié)點(diǎn)的左唤殴、右節(jié)點(diǎn)依次插入隊(duì)列,B在隊(duì)首到腥,C在隊(duì)尾朵逝,(B,C)乡范,此時(shí)得到A節(jié)點(diǎn)配名;

  • 繼續(xù)彈出隊(duì)首元素啤咽,即彈出B,并將B的左渠脉、右節(jié)點(diǎn)插入隊(duì)列宇整,C在隊(duì)首,E在隊(duì)尾(C,D芋膘,E)鳞青,此時(shí)得到B節(jié)點(diǎn);

  • 繼續(xù)彈出为朋,即彈出C臂拓,并將C節(jié)點(diǎn)的左、中习寸、右節(jié)點(diǎn)依次插入隊(duì)列胶惰,(D,E,F,G,H),此時(shí)得到C節(jié)點(diǎn)霞溪;

  • 將D彈出孵滞,此時(shí)D沒有子節(jié)點(diǎn),隊(duì)列中元素為(E,F,G,H)鸯匹,得到D節(jié)點(diǎn)坊饶; 。殴蓬。幼东。以此類推。科雳。

  • 2.深度優(yōu)先遍歷 英文縮寫為DFS即Depth First Search.其過程簡(jiǎn)要來說是對(duì)每一個(gè)可能的分支路徑深入到不能再深入為止,而且每個(gè)節(jié)點(diǎn)只能訪問一次脓杉。對(duì)于上面的例子來說深度優(yōu)先遍歷的結(jié)果就是:A,B,D,E,I,C,F,G,H.(假設(shè)先走子節(jié)點(diǎn)的的左側(cè))糟秘。

  • 深度優(yōu)先遍歷各個(gè)節(jié)點(diǎn),需要使用到棧(Stack)這種數(shù)據(jù)結(jié)構(gòu)球散。stack的特點(diǎn)是是先進(jìn)后出尿赚。整個(gè)遍歷過程如下:

  • 先往棧中壓入右節(jié)點(diǎn),再壓左節(jié)點(diǎn)蕉堰,這樣出棧就是先左節(jié)點(diǎn)后右節(jié)點(diǎn)了凌净。 首先將A節(jié)點(diǎn)壓入棧中,stack(A);

  • 將A節(jié)點(diǎn)彈出屋讶,同時(shí)將A的子節(jié)點(diǎn)C冰寻,B壓入棧中,此時(shí)B在棧的頂部皿渗,stack(B,C)斩芭;

  • 將B節(jié)點(diǎn)彈出轻腺,同時(shí)將B的子節(jié)點(diǎn)E,D壓入棧中划乖,此時(shí)D在棧的頂部贬养,stack(D,E,C);

  • 將D節(jié)點(diǎn)彈出琴庵,沒有子節(jié)點(diǎn)壓入,此時(shí)E在棧的頂部误算,stack(E,C)迷殿; 將E節(jié)點(diǎn)彈出儿礼,同時(shí)將E的子節(jié)點(diǎn)I壓入,stack(I,C)贪庙;

  • …依次往下蜘犁,最終遍歷完成。 代碼:也是以二叉樹為例止邮。

29.for in和for of的區(qū)別

  • 推薦在循環(huán)對(duì)象屬性的時(shí)候这橙,使用for...in,在遍歷數(shù)組的時(shí)候的時(shí)候使用for...of
  • for...in循環(huán)出的是key,for...of循環(huán)出的是value
  • 注意导披,for...of是ES6新引入的特性屈扎。修復(fù)了ES5引入的for...in的不足
  • for...of不能循環(huán)普通的對(duì)象,需要通過和Object.keys()搭配使用

typeof和instanceof 區(qū)別撩匕?

  • 在javascript中鹰晨,判斷一個(gè)變量的類型可以用typeof
  • 數(shù)字類型、typeof返回的值是number止毕。比如說:typeof(1)模蜡,返回值是number
  • 字符串類型,typeof返回的值是string扁凛。比如typeof(“123”返回值時(shí)string)
  • 布爾類型忍疾,typeof返回的值是boolean。比如typeof(true)返回值時(shí)boolean
  • 對(duì)象谨朝、數(shù)組卤妒、null返回的值是object。比如typeof(window)字币,typeof(document)则披,typeof(null)返回的值都是object
  • 函數(shù)類型,返回的值是function洗出。比如:typeof(eval)士复,typeof(Date)返回的值都是function。
  • 不存在的變量翩活、函數(shù)或者undefined判没,將返回undefined蜓萄。比如:typeof(abc)、typeof(undefined)都返回undefined
  • 在javascript中澄峰,instanceof用于判斷某個(gè)對(duì)象是否被另一個(gè)函數(shù)構(gòu)造嫉沽。
  • 使用typeof運(yùn)算符時(shí)采用引用類型存儲(chǔ)值會(huì)出現(xiàn)一個(gè)問題,無論引用的是什么類型的對(duì)象俏竞,它都返回”object”绸硕。ECMAScript引入了另一個(gè)Java運(yùn)算符instanceof來解決這個(gè)問題。Instanceof運(yùn)算符與typeof運(yùn)算符相似魂毁,用于識(shí)別正在處理的對(duì)象的類型玻佩。與typeof方法不同的是,instanceof方法要求開發(fā)者明確地確認(rèn)對(duì)象為某特定類型

常見的繼承有幾種方法?

  • 原型鏈繼承
  • 構(gòu)造函數(shù)繼承(經(jīng)典繼承)
  • 組合方式繼承(構(gòu)造函數(shù) + 原型鏈)
  • es6方法繼承

什么是事件冒泡席楚,它是如何工作的咬崔?如何阻止事件冒泡?

在一個(gè)對(duì)象上觸發(fā)某類事件(比如單擊onclick事件),如果此對(duì)象定義了此事件的處理程序烦秩,那么此事件就會(huì)調(diào)用這個(gè)處理程序垮斯,如果沒有定義此事件處理程序或者事件返回true,那么這個(gè)事件會(huì)向這個(gè)對(duì)象的父級(jí)對(duì)象傳播只祠,從里到外兜蠕,直至它被處理(父級(jí)對(duì)象所有同類事件都將被激活),或者它到達(dá)了對(duì)象層次的最頂層抛寝,即document對(duì)象(有些瀏覽器是window)

//阻止事件冒泡的幾種方法 
//第一種
event.stopPropagation(); 
//第二種
return false; 
//第三種
event.preventDefault();

什么是Promise對(duì)象熊杨,有哪些用法、通過Promise對(duì)象實(shí)現(xiàn)ajax

  • Promise是異步編程的一種解決方案盗舰,它是一個(gè)容器晶府,里面保存著某個(gè)未來才會(huì)結(jié)束的事件(通常是一個(gè)異步操作)的結(jié)果。 Promise 提供統(tǒng)一的API钻趋,各種異步操作都可以用同樣的方法進(jìn)行處理郊霎。promise對(duì)象是一個(gè)構(gòu)造函數(shù),用來生成Promise實(shí)例爷绘;

  • Promise對(duì)象的特點(diǎn)

    • 對(duì)象的狀態(tài)不受外界影響,promise對(duì)象代表一個(gè)異步操作进倍,有三種狀態(tài)土至,pending(進(jìn)行中)、fulfilled(已成功)猾昆、rejected(已失斕找颉)。只有異步操作的結(jié)果垂蜗,可以決定當(dāng)前是哪一種狀態(tài)楷扬,任何其他操作都無法改變這個(gè)狀態(tài)解幽。
    • 一旦狀態(tài)改變就不會(huì)再變,任何時(shí)候都可以得到這個(gè)結(jié)果烘苹,promise對(duì)象的狀態(tài)改變躲株,只有兩種可能:從pending變?yōu)閒ulfilled,從pending變?yōu)閞ejected镣衡。
  • Promise缺點(diǎn)霜定。

    • 無法取消Promise,一旦新建它就會(huì)立即執(zhí)行廊鸥,無法中途取消望浩。
    • 如果不設(shè)置回調(diào)函數(shù),Promise內(nèi)部拋出的錯(cuò)誤惰说,不會(huì)反應(yīng)到外部磨德。
    • 當(dāng)處于pending狀態(tài)時(shí),無法得知目前進(jìn)展到哪一個(gè)階段
  • Promise對(duì)象的用法

    • 是一個(gè)構(gòu)造函數(shù)吆视,這個(gè)構(gòu)造函數(shù)里有兩個(gè)參數(shù)典挑,分別是:resolve(成功之后的回調(diào)函數(shù))、reject(失敗之后的回調(diào)函數(shù))揩环。


      2374931195-5d883df9072f6_articlex.png

      promise實(shí)例生成以后搔弄,可以用then方法分別指定resolved狀態(tài)和rejected狀態(tài)的回調(diào)函數(shù)


      3033114998-5d883e02ec354_articlex.png

      then方法可以接受連個(gè)回調(diào)函數(shù)作為參數(shù),第一個(gè)回調(diào)函數(shù)是promise對(duì)象的狀態(tài)變?yōu)閞esolved時(shí)調(diào)用丰滑,第二個(gè)回調(diào)函數(shù)是promise對(duì)象的狀態(tài)變?yōu)閞ejected時(shí)調(diào)用顾犹,其中,第二個(gè)函數(shù)是可選的褒墨,不一定要提供炫刷,這兩個(gè)函數(shù)都接受promise對(duì)象傳出的值作為參數(shù);then指定回調(diào)函數(shù)的時(shí)候郁妈,成功的回調(diào)函數(shù)必須傳浑玛,失敗的回調(diào)函數(shù)可以勝利。 如果前面的promise執(zhí)行失敗噩咪,不詳影響后續(xù)操作終止顾彰,捕獲異常的兩種方式:
      ①可以為每個(gè)promise指定失敗回調(diào);

      function(err){ console.log(……) })
      ②最后加catch(function(err){console.log(……) })//表示如前面有任意一個(gè)有報(bào)錯(cuò)胃碾,立即報(bào)錯(cuò)涨享,并終止后面的;如果前面無報(bào)錯(cuò)仆百,前面正常執(zhí)行厕隧。

  • Promise對(duì)象實(shí)現(xiàn)ajax


    591937307-5d883e11d8774_articlex.png

什么是閉包,舉個(gè)例子說明一下?

閉包就是能夠讀取其他函數(shù)內(nèi)部變量的函數(shù)。例如在javascript中吁讨,只有函數(shù)內(nèi)部的子函數(shù)才能讀取局部變量髓迎,所以閉包可以理解成“定義在一個(gè)函數(shù)內(nèi)部的函數(shù)“。在本質(zhì)上建丧,閉包是將函數(shù)內(nèi)部和函數(shù)外部連接起來的橋梁排龄。
創(chuàng)建閉包最常見方式,就是在一個(gè)函數(shù)內(nèi)部創(chuàng)建另一個(gè)函數(shù)茶鹃。下面例子中的 closure 就是一個(gè)閉包涣雕,

  function func(){ 
     va ra =1 ,b = 2; 
     funciton closure(){
          return a+b; 
     } 
     return  closure; 
   }

let、var闭翩、const區(qū)別

  • var聲明的變量會(huì)掛載在window上挣郭,而let和const聲明的變量不會(huì)
  • var聲明變量存在變量提升,let和const不存在變量提升
  • let和const聲明形成塊作用域疗韵,var變量提升不會(huì)形成作用域
  • 同一作用域下let和const不能聲明同名變量兑障,而var可以
  • var和let可以可以修改聲明的變量,const不可以
  • const定義的變量時(shí)必須初始化
  • let蕉汪、const 存在暫時(shí)性死區(qū)

apply流译、call、bind 什么區(qū)別者疤?

  • 這三者的作用就是改變函數(shù)運(yùn)行時(shí)this的指向福澡。

  • call和apply都是對(duì)函數(shù)的直接調(diào)用,而bind方法返回的仍然是一個(gè)函數(shù)驹马,因此后面還需要()來進(jìn)行調(diào)用才可以革砸。

  • call后面的參數(shù)與say方法中是一一對(duì)應(yīng)的,而apply的第二個(gè)參數(shù)是一個(gè)數(shù)組糯累,數(shù)組中的元素是和方法中一一對(duì)應(yīng)的算利。

  • bind傳參

     xw.say.bind(xh,"實(shí)驗(yàn)小學(xué)","六年級(jí)")();
     xw.say.bind(xh)("實(shí)驗(yàn)小學(xué)","六年級(jí)");
    
  • call

     語法:call([thisObj[,arg1[, arg2[, [,.argN]]]]]) 
    
    • 定義:調(diào)用一個(gè)對(duì)象的一個(gè)方法,以另一個(gè)對(duì)象替換當(dāng)前對(duì)象泳姐。
    • 說明:call方法可以用來代替另一個(gè)對(duì)象調(diào)用一個(gè)方法效拭。call 方法可將一個(gè)函數(shù)的對(duì)象上下文從初始的上下文改變?yōu)橛?thisObj 指定的新對(duì)象。如果沒有提供 thisObj 參數(shù)胖秒,那么 Global 對(duì)象被用作 thisObj缎患。
  • apply

    語法:apply([thisObj[,argArray]])
    
    • 定義:應(yīng)用某一對(duì)象的一個(gè)方法,用另一個(gè)對(duì)象替換當(dāng)前對(duì)象阎肝。
    • 說明:如果argArray 不是一個(gè)有效的數(shù)組或者不是 arguments 對(duì)象挤渔,那么將導(dǎo)致一個(gè) TypeError。如果沒有提供 argArray 和 thisObj 任何一個(gè)參數(shù)盗痒,那么 Global 對(duì)象將被用作 thisObj, 并且無法被傳遞任何參數(shù)。
  • bind

    語法:bind(thisArg[, arg1[, arg2[, ...]]])
    
    • 定義:將接受多個(gè)參數(shù)的函數(shù)變換成接受一個(gè)單一參數(shù)俯邓。
    • 說明:bind()方法所返回的函數(shù)的length(形參數(shù)量)等于原函數(shù)的形參數(shù)量減去傳入bind()方法中的實(shí)參數(shù)量(第一個(gè)參數(shù)以后的所有參數(shù))骡楼,因?yàn)閭魅隻ind中的實(shí)參都會(huì)綁定到原函數(shù)的形參。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末稽鞭,一起剝皮案震驚了整個(gè)濱河市鸟整,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌朦蕴,老刑警劉巖篮条,帶你破解...
    沈念sama閱讀 212,718評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異吩抓,居然都是意外死亡涉茧,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門疹娶,熙熙樓的掌柜王于貴愁眉苦臉地迎上來伴栓,“玉大人,你說我怎么就攤上這事雨饺∏澹” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵额港,是天一觀的道長(zhǎng)饺窿。 經(jīng)常有香客問我,道長(zhǎng)移斩,這世上最難降的妖魔是什么肚医? 我笑而不...
    開封第一講書人閱讀 56,755評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮叹哭,結(jié)果婚禮上忍宋,老公的妹妹穿的比我還像新娘。我一直安慰自己风罩,他們只是感情好糠排,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著超升,像睡著了一般入宦。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上室琢,一...
    開封第一講書人閱讀 50,050評(píng)論 1 291
  • 那天乾闰,我揣著相機(jī)與錄音,去河邊找鬼盈滴。 笑死涯肩,一個(gè)胖子當(dāng)著我的面吹牛轿钠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播病苗,決...
    沈念sama閱讀 39,136評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼疗垛,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了硫朦?” 一聲冷哼從身側(cè)響起贷腕,我...
    開封第一講書人閱讀 37,882評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎咬展,沒想到半個(gè)月后泽裳,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡破婆,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評(píng)論 2 327
  • 正文 我和宋清朗相戀三年涮总,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荠割。...
    茶點(diǎn)故事閱讀 38,789評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡妹卿,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蔑鹦,到底是詐尸還是另有隱情夺克,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評(píng)論 4 333
  • 正文 年R本政府宣布嚎朽,位于F島的核電站铺纽,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏哟忍。R本人自食惡果不足惜狡门,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望锅很。 院中可真熱鬧其馏,春花似錦、人聲如沸爆安。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽扔仓。三九已至褐奥,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翘簇,已是汗流浹背撬码。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評(píng)論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留版保,地道東北人呜笑。 一個(gè)月前我還...
    沈念sama閱讀 46,598評(píng)論 2 362
  • 正文 我出身青樓夫否,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國和親叫胁。 傳聞我的和親對(duì)象是個(gè)殘疾皇子慷吊,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評(píng)論 2 351

推薦閱讀更多精彩內(nèi)容

  • JavaScript的組成 JavaScript 由以下三部分組成:ECMAScript(核心):JavaScri...
    紋小艾閱讀 3,174評(píng)論 0 3
  • 相對(duì)于回調(diào)函數(shù)來說,Promise是一種相對(duì)優(yōu)雅的選擇曹抬。那么有沒有更好的方案呢?答案就是async/await急鳄。優(yōu)...
    勇往直前888閱讀 47,190評(píng)論 8 36
  • JavaScript語言的執(zhí)行環(huán)境是‘單線程’的(也就是說谤民,執(zhí)行后續(xù)的代碼之前必須完成前面的任務(wù),也就是采用的是阻...
    kim_jin閱讀 575評(píng)論 0 0
  • @轉(zhuǎn)自GitHub 介紹js的基本數(shù)據(jù)類型。Undefined疾宏、Null张足、Boolean、Number坎藐、Strin...
    YT_Zou閱讀 1,147評(píng)論 0 0
  • 開始之前 JavaScript是單線程語言为牍,所以都是同步執(zhí)行的,要實(shí)現(xiàn)異步就得通過回調(diào)函數(shù)的方式岩馍,但是過多的回調(diào)會(huì)...
    Geeker工作坊閱讀 417評(píng)論 0 1