Vue是以數據爲驅動的,Vue自身將DOM和數據進行綁定,一旦建立綁定,DOM和數據將保持同步,每當數據發生變化,DOM會跟着變化。
ViewModel是Vue的核心,它是Vue的一個實例。Vue實例時做用域的這個HTML元素能夠是body,也能夠是某個id所指代的元素。
DOMListeners和DataBindings是實現雙向綁定的關鍵。
DOMListeners監聽頁面全部View層DOM元素的變化,當發生變化,Model層的數據隨之變化;
DataBindings監聽Model層的數據,當數據發生變化,View層的DOM元素隨之變化。
MVVM框架提倡把渲染和邏輯分離。簡單來講就是不要再讓 JS
直接操控 DOM
,JS
只須要管理狀態便可,而後再經過一種模板語法來描述狀態和界面結構的關係。
24.v-show
和v-if
指令的共同點和不一樣點?
v-show
指令是經過修改元素的display
CSS屬性讓其顯示或者隱藏
v-if
指令是直接銷燬和重建DOM達到讓元素顯示和隱藏的效果
25.keep-alive
keep-alive是Vue提供的一個抽象組件,用來對組件進行緩存,從而節省性能,因爲是一個抽象組件,因此在vue頁面渲染完畢後不會被渲染成一個DOM元素
https://www.jianshu.com/p/4b55d312d297
26.Vue生命週期
1)beforeCreate:
完成實例初始化,初始化非響應式變量;
this指向建立的實例;
能夠加載loading事件;
data computed watch methods 上的方法和數據均不能訪問;
2)created:
實例建立完成;
完成數據(data props computed)的初始化,導入依賴項;
可訪問data computed watch methods上的數據和方法;
未掛載DOM,不能訪問$el,$ref爲空;
可在這結束loading,還能作一些初始化,實現函數自執行;
能夠對data數據進行操做,可進行一些請求,請求不易過多,避免白屏時間太長;
若在此階段進行的 DOM 操做必定要放在 Vue.nextTick() 的回調函數中
3)beforeMount:
有了el,編譯了template/outerHTML;
能找到對應的template,並編譯成render函數;
4)mounted:
完成建立vm.$el,和雙向綁定;
完成掛載DOM 和渲染;可在mounted鉤子對掛載的dom進行操做;
即有了DOM 且完成了雙向綁定,可訪問DOM節點,$ref;
可在這發起後端請求,拿回數據,配合路由鉤子作一些事情;
可對DOM 進行操做;
5)beforeUpdate:
數據更新以前;
可在更新前訪問現有的DOM,如手動移除添加的事件監聽器;
6)updated:
完成虛擬DOM的從新渲染和打補丁;
組件DOM 已完成更新;
可執行依賴的dom 操做;
注意:不要在此函數中操做數據,會陷入死循環的。
7)activated:
在使用vue-router時有時須要使用<keep-alive></keep-alive>來緩存組件狀態,這個時候created鉤子就不會被重複調用了
若是咱們的子組件須要在每次加載的時候進行某些操做,可使用activated鉤子觸發
8)deactivated:
keep-alive 組件被移除時使用
9)beforeDestory:
在執行app.$destroy()以前
可作一些刪除提示,如:你確認刪除XX嗎?
可用於銷燬定時器,解綁全局時間 銷燬插件對象
10)destroyed:
當前組件已被刪除,銷燬監聽事件 組件 事件 子實例也被銷燬
這時組件已經沒有了,你沒法操做裏面的任何東西了
http://www.javashuo.com/article/p-mzpconrz-ge.html
27.父子組件的生命週期?
僅當子組件完成掛載後,父組件纔會掛載
當子組件完成掛載後,父組件會主動執行一次beforeUpdate/updated鉤子函數(僅首次)
父子組件在data變化中是分別監控的,可是在更新props中的數據是關聯的(可實踐)
銷燬父組件時,先將子組件銷燬後纔會銷燬父組件
兄弟組件的初始化(mounted以前)分開進行,掛載是從上到下依次進行
當沒有數據關聯時,兄弟組件之間的更新和銷燬是互不關聯的
28.什麼是Vue的生命週期?
Vue實例從建立到銷燬的過程,就是生命週期。
29.Vue生命週期的做用是什麼?
Vue生命週期有不少事件鉤子,讓咱們在控制整個Vue實例的過程更容易造成好的邏輯。
30.Vue生命週期總共有幾個階段?
答:它能夠總共分爲8個階段:建立前/後, 載入前/後,更新前/後,銷燬前/銷燬後。
31.Vue雙向綁定的原理是什麼?
Vue採用的是數據劫持結合發佈和-訂閱者模式的方式,經過Object.defineProperty()來劫持各個屬性的setter,getter,在數據變更時發佈消息給訂閱者,觸發相應的監聽回調
http://www.javashuo.com/article/p-pvlyorwx-hu.html
32.Vue組件之間的參數傳遞?
1.父組件與子組件傳值
父組件傳給子組件:子組件經過props方法接受數據;
子組件傳給父組件:$emit方法傳遞參數
2.非父子組件間的數據傳遞,兄弟組件傳值
eventBus,就是建立一個事件中心,至關於中轉站,能夠用它來傳遞事件和接收事件。項目比較小時,用這個比較合適。
(雖然也有很多人推薦直接用VUEX,具體來講看需求咯。技術只是手段,目的達到纔是王道。)
33.Vuex中有5中默認的基礎對象
- state:存儲狀態(變量)
- getters:對數據獲取以前的再次編譯,能夠理解爲state的計算屬性。咱們在組件中使用 $sotre.getters.fun()
- mutations:修改狀態,而且是同步的。在組件中使用$store.commit('',params)。這個和咱們組件中的自定義事件相似。
- actions:異步操做。在組件中使用是$store.dispath('')
- modules:store的子模塊,爲了開發大型項目,方便狀態管理而使用的。這裏咱們就不解釋了,用起來和上面的同樣。
34.Vuex是什麼?
答:vuex 是一個專門爲vue.js應用程序開發的狀態管理模式。
這個狀態咱們能夠理解爲在data中的屬性,須要共享給其餘組件使用的部分。
也就是說,是咱們須要共享的data,使用vuex進行統一集中式的管理。
35.Vuex使用
http://www.javashuo.com/article/p-fdwnabwi-go.html
36.Vuex中mutation和action的區別
答:mutation 有必須同步執行這個限制,Action 就不受約束!咱們能夠在 action 內部執行異步操做
http://www.javashuo.com/article/p-enotvqwo-gn.html
37.原型、原型鏈、constructor
每一個函數都有一個prototype屬性,prototype是函數的原型對象。原型對象是用來給實例共享屬性和方法的
Javascript中全部的對象都是Object的實例,並繼承Object.prototype的屬性和方法,也就是說,Object.prototype是全部對象的爸爸
每一個對象都有__proto__屬性,這個__proto__指向的是建立這個對象的構造函數的prototype
Javascript語言的繼承機制一直很難被人理解
它沒有"子類"和"父類"的概念,也沒有"類"(class)和"實例"(instance)的區分,全靠一種很奇特的"原型鏈"(prototype chain)模式,來實現繼承
每一個對象都有一個constructor屬性,它引用了初始化該對象的構造函數
http://www.javashuo.com/article/p-xnxtvxpv-gn.html
http://www.ruanyifeng.com/blog/2011/06/designing_ideas_of_inheritance_mechanism_in_javascript.html
38.JS的基本數據類型和引用數據類型以及深拷貝和淺拷貝
基本數據類型:
他們的值在內存中佔據着固定大小的空間,並被保存在棧內存中;
當一個變量向另外一個變量複製基本類型的值,會建立這個值的副本,而且咱們不能給基本數據類型的值添加屬性;
Undefined / Null / Boolean / Number / String,它們是直接按值存放的,能夠直接訪問。
引用數據類型:(對象、函數、數組)
複雜的數據類型便是引用類型,它的值是對象,保存在堆內存中,包含引用類型值的變量實際上包含的不是對象自己,而是一個指向該對象的指針;
從一個變量向另外一個變量複製引用類型的值,複製的實際上是指針地址而已,所以兩個變量最終都指向同一個對象。
訪問引用數據類型的值時,首先從棧中得到該對象的地址指針,而後再從堆內存中取得所需的數據。
淺拷貝:是拷貝一層,深層次的對象級別的就拷貝引用;
深拷貝:是拷貝多層,每一級別的數據都會拷貝出來;
淺拷貝的時候若是數據是基本數據類型,那麼就如同直接賦值那種,會拷貝其自己,若是除了基本數據類型以外還有一層對象,那麼對於淺拷貝而言就只能拷貝其引用,對象的改變會反應到拷貝對象上;
可是深拷貝就會拷貝多層,即便是嵌套了對象,也會都拷貝出來。
當咱們使用對象拷貝時,若是屬性是對象或數組時,這時咱們傳遞的只是一個地址。所以子對象在訪問該屬性時,會根據地址回溯到父對象指向的堆內存中,即父子對象發生了關聯,二者的屬性值會指向同一內存空間。
看一個比較經典的面試題:
var a = function() {console.log(11)};
var b = function() {console.log(11)};
console.log( a==b ); //false
console.log( {}=={} ); //false
console.log( []==[] ); //false
爲何結果都是false?
變量 a 實際保存的是指向堆內存中對象的一個指針,而 b 保存的是指向堆內存中另外一個對象的一個指針;
雖然這兩個對象的值是同樣的,但它們是獨立的2個對象,佔了2分內存空間;因此 a == b 爲 false
var a = {};
var b = a;
console.log( a == b ); // true
這時變量 b 複製了變量 a 保存的指針,它們都指向堆內存中同一個對象;因此 a == b 爲 true
傳值與傳址:
基本類型與引用類型最大的區別實際就是 傳值 與 傳址 的區別
var a = [1,2,3,4,5];
var b = a;
var c = a[0];
console.log(b); // [1,2,3,4,5]
console.log(c); // 1
b[4] = 6;
c = 7;
console.log(a[4]); //6
console.log(a[0]); //1
從上面代碼能夠得知,當改變b中的數據時,a也發生了變化;可是當咱們改變c的數值時,a卻沒有發生改變
這就是傳值與傳址的區別。由於a是數組,屬於引用類型,因此a給b傳的是棧中的地址,而不是堆內存中的對象。
而c僅僅是從a堆內存中獲取的一個數值,並保存在棧中。因此b修改的時候,會根據地址回到a堆內存中修改;c則直接在棧中修改,而且不能指向a堆內存中。
https://blog.csdn.net/Bruce__taotao/article/details/82690506
https://www.cnblogs.com/c2016c/articles/9328725.html
https://blog.csdn.net/weixin_37719279/article/details/81240658
39.什麼是遞歸?
https://pushy.site/2018/02/20/recursion/
40.什麼是閉包?閉包有什麼做用?使用閉包的好處是什麼?
41.什麼是變量做用域?
變量的做用域就兩種:全局變量和局部變量
全局做用域:
最外層函數定義的變量擁有全局做用域,即對任何內部函數來講,都是能夠訪問的
局部做用域:
和全局做用域相反,局部做用域通常只在固定的代碼片斷內可訪問到,而對於函數外部是沒法訪問的,最多見的例如函數內部
<script>
function fn(){ var innerVar = "inner"; } fn(); console.log(innerVar);// ReferenceError: innerVar is not defined
</script>
須要注意的是,函數內部聲明變量的時候,必定要使用var命令。若是不用的話,你實際上聲明瞭一個全局變量!
<script>
function fn(){ innerVar = "inner"; } fn(); console.log(innerVar);// result:inner
</script>
再來看一個代碼:
<script>
var scope = "global"; function fn(){ console.log(scope);//result:undefined
var scope = "local"; console.log(scope);//result:local;
} fn(); </script>
頗有趣吧,第一個輸出竟然是undefined,本來覺得它會訪問外部的全局變量(scope=」global」),可是並無。
這能夠算是javascript的一個特色,只要函數內定義了一個局部變量,函數在解析的時候都會將這個變量「提早聲明」:
<script>
var scope = "global"; function fn(){ var scope;//提早聲明瞭局部變量
console.log(scope);//result:undefined
scope = "local"; console.log(scope);//result:local;
} fn(); </script>
然而,也不能所以草率地將局部做用域定義爲:用var聲明的變量做用範圍起止於花括號之間。
javascript並無塊級做用域
那什麼是塊級做用域?
像在C/C++中,花括號內中的每一段代碼都具備各自的做用域,並且變量在聲明它們的代碼段以外是不可見的,好比下面的c語言代碼:
for(int i = 0; i < 10; i++){ //i的做用範圍只在這個for循環
} printf("%d",&i);//error
可是javascript不一樣,並無所謂的塊級做用域,javascript的做用域是相對函數而言的,能夠稱爲函數做用域:
<script>
for(var i = 1; i < 10; i++){ //coding
} console.log(i); //10
</script>
42.什麼是做用域鏈?什麼是執行環境?
個人理解就是,根據在內部函數能夠訪問外部函數變量的這種機制,用鏈式查找決定哪些數據能被內部函數訪問。
想要知道js怎麼鏈式查找,就得先了解js的執行環境
每一個函數運行時都會產生一個執行環境,而這個執行環境怎麼表示呢?js爲每個執行環境關聯了一個變量對象。環境中定義的全部變量和函數都保存在這個對象中。
全局執行環境是最外圍的執行環境,全局執行環境被認爲是window對象,所以全部的全局變量和函數都做爲window對象的屬性和方法建立的。
js的執行順序是根據函數的調用來決定的,當一個函數被調用時,該函數環境的變量對象就被壓入一個環境棧中。而在函數執行以後,棧將該函數的變量對象彈出,把控制權交給以前的執行環境變量對象。
舉個例子:
<script>
var scope = "global";
function fn1(){
return scope;
}
function fn2(){
return scope;
}
fn1();
fn2();
</script>
上面代碼執行狀況演示:
![執行環境](http://static.javashuo.com/static/loading.gif)
http://www.javashuo.com/article/p-expedgrq-ku.html
43.Vue組件
https://www.jianshu.com/p/7e825cd5f086
44.優化圖片加載的方法有哪些?
a. 圖片懶加載,滾動到相應位置才加載圖片。
b. 圖片預加載,若是爲幻燈片、相冊等,將當前展現圖片的前一張和後一張優先下載。
c. 使用CSSsprite,SVGsprite,Iconfont、Base64等技術,若是圖片爲css圖片的話。
d. 若是圖片過大,可使用特殊編碼的圖片,加載時會先加載一張壓縮的特別厲害的縮略圖,以提升用戶體驗。
45.什麼是token驗證?
Token是在客戶端頻繁向服務端請求數據,服務端頻繁的去數據庫查詢用戶名和密碼並進行對比,判斷用戶名和密碼正確與否,並做出相應提示,在這樣的背景下,Token便應運而生。
Token是服務端生成的一串字符串,以做客戶端進行請求的一個令牌,當第一次登陸後,服務器生成一個Token便將此Token返回給客戶端,之後客戶端只需帶上這個Token前來請求數據即
可,無需再次帶上用戶名和密碼。
46.使用基於 Token 的身份驗證方法,在服務端不須要存儲用戶的登陸記錄。大概的流程是這樣的:
1.客戶端使用用戶名跟密碼請求登陸
2.服務端收到請求,去驗證用戶名與密碼
3.驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
4.客戶端收到 Token 之後能夠把它存儲起來,好比放在 Cookie 裏或者 Local Storage 裏
5.客戶端每次向服務端請求資源的時候須要帶着服務端簽發的 Token
6.服務端收到請求,而後去驗證客戶端請求裏面帶着的 Token,若是驗證成功,就向客戶端返回請求的數據
47.堆、棧
棧(stack):先進後出;自動分配內存空間,由系統自動釋放;使用的是一級緩存,他們一般都是被調用時處於存儲空間中,調用完當即釋放。
堆(heap):隊列優先,先進先出;動態分配內存,大小不定也不會自動釋放;存放在二級緩存中,生命週期由虛擬機的垃圾回收算法來決定;通常由程序員分配釋放,若程序員不釋放,程序結束時可能由OS回收。
48.js中 == 和 === 有什麼區別?
== 用於通常比較,=== 用於嚴格比較,== 在比較的時候能夠轉換數據類型,=== 嚴格比較,只要類型不匹配就返回 flase
49.JS語言特色
JS做爲腳本語言,它的主要用途是與用戶互動,以及操做DOM。這決定了它只能是單線程,不然會帶來很複雜的同步問題,也就是同一時刻只能作一件事情。全部任務只能在一個線程上完成,一次只能作一件事。前面的任務沒作完,後面的任務只能等着。
可是隨着業務的不斷增長,只是單純的單線程模式已經可能沒法知足咱們的需求了。因而在html5中新增了後臺任務worker API。
瀏覽器的線程,瀏覽器中主要的線程包括,UI渲染線程,JS主線程,GUI事件觸發線程,http請求線程
看一個經典的面試題:
function a() {
setTimeout(function () {
alert(1)
}, 0);
alert(2);
}
a();
代碼中的 setTimeout
設爲 0,也就是延遲 0ms,看上去是不作任何延遲馬上執行,即依次彈出 「1」、「2」。但實際的執行結果確是 「2」、「1」。其中的緣由得從 setTimeout
的原理提及:
JavaScript 是單線程執行的,也就是沒法同時執行多段代碼,當某一段代碼正在執行的時候,全部後續的任務都必須等待,造成一個隊列,一旦當前任務執行完畢,再從隊列中取出下一個任務。這也常被稱爲 「阻塞式執行」。
因此一次鼠標點擊,或是計時器到達時間點,或是 Ajax 請求完成觸發了回調函數,這些事件處理程序或回調函數都不會當即運行,而是當即排隊,一旦線程有空閒就執行。
假如當前 JavaScript 進程正在執行一段很耗時的代碼,此時發生了一次鼠標點擊,那麼事件處理程序就被阻塞,用戶也沒法當即看到反饋,事件處理程序會被放入任務隊列,直到前面的代碼結束之後纔會開始執行。
setTimeout(fn, 0)的含義是,指定某個任務在主線程最先可得的空閒時間執行,也就是說,當前代碼執行完(執行棧清空)之後,儘量的早執行。它在「任務隊列」的尾部添加一個事件,所以要等到同步任務和「任務隊列」現有的事件都處理完,纔會獲得執行。
HTML5標準規定了setTimeout()的第二個參數的最小值不得小於4毫秒,若是低於這個值,則默認是4毫秒。在此以前。老版本的瀏覽器都將最短期設爲10毫秒。另外,對於那些DOM的變更(尤爲是涉及頁面從新渲染的部分),一般是間隔16毫秒執行。這時使用requestAnimationFrame()的效果要好於setTimeout();
注意:setTimeout()只是將事件插入了「任務隊列」,必須等當前代碼(執行棧)執行完,主線程纔會去執行它指定的回調函數。要是當前代碼消耗時間很長,也有可能要等好久,因此並沒辦法保證回調函數必定會在setTimeout()指定的時間執行。因此,setTimeout()的第二個參數表示的是最少時間,並不是是確切時間。
settimeout(0)就起到了一個將事件加入到隊列中,待執行的一個功能效果!
定時器佔用cpu較多,建議酌情使用。
50.如何實現js的多線程?
JS爲咱們提供了一個Worker類,它的做用就是爲了解決這種阻塞的現象。當咱們使用這個類的時候,它就會向瀏覽器申請一個新的線程。這個線程就用來單獨執行一個js文件。
Web Worker 是運行在後臺的 JavaScript,獨立於其餘腳本,不會影響頁面的性能。您能夠繼續作任何願意作的事情:點擊、選取內容等等,而此時 Web Worker 在後臺運行。
Worker就是爲了JavaScript 創造多線程環境,容許主線程建立 Worker 線程,將一些任務分配給後者運行。
開啓後臺線程,在不影響前臺線程的前提下作一些耗時或者異步的操做。
由於是不一樣的線程,因此主線程與worker線程互不干擾。也不會相互打斷。因此在一些場景能夠提升頁面的流程性。Worker 線程一旦新建成功,就會始終運行,不會被主線程上的活動(好比用戶點擊按鈕、提交表單)打斷。這樣有利於隨時響應主線程的通訊。
可是,這也形成了 Worker 比較耗費資源,不該該過分使用,並且一旦使用完畢,就應該關閉。
var worker = new Worker(js文件路徑); // 這個語句就會申請一個線程用來執行這個js文件
固然,在主線程中有一些方法來實現對新線程的控制和數據的接收。在這裏,咱們只說比較經常使用的幾個方法。
//postMessage(msg);
//postMessage方法把在新線程執行的結果發送到瀏覽器的js引擎線程裏
worker.onmessage = function(){
//獲取在新線程中執行的js文件發送的數據 用event.data接收數據
console.log( event.data )
};
setTimeout( function(){
worker.terminate();
//terminate方法用於關閉worker線程
},2000)
setTimeout( function(){
worker = new Worker("js/test22.js");
//再次開啓worker線程
},3000)
使用規則:
- 必須同源:也就是說js文件的路徑必須和主線程的腳本同源。防止了外部引用。
- dom限制:在worker線程中不能操做dom(document,window,parent)。注意可使用瀏覽器的navigator和location對象。
- 通信限制:worker線程和主線程不在一個上下文中因此不能直接通信。也就是說主線程定義的變量在worker中也是不能使用的。全部只能經過消息完成。
- 提示禁止:worker線程不能alert和confirm,這個不知到具體緣由?
- 傳值dom:進行消息通信也不能傳值dom只能是變量。
- ie限制:ie9不能使用!ie9不能使用!ie9不能使用!
https://www.cnblogs.com/yanbigfeg/p/9546599.html#_label0
51.瀏覽器緩存機制
以上兩點結論就是瀏覽器緩存機制的關鍵,它確保了每一個請求的緩存存入與讀取
根據是否須要向服務器從新發起HTTP請求將緩存過程分爲兩個部分,分別是強緩存和協商緩存
強緩存:不會向服務器發送請求,直接從緩存中讀取資源,在chrome控制檯的Network選項中能夠看到該請求返回200的狀態碼,而且Size顯示from disk cache或from memory cache。強緩存能夠經過設置兩種 HTTP Header 實現:Expires 和 Cache-Control
強緩存判斷是否緩存的依據來自因而否超出某個時間或者某個時間段,而不關心服務器端文件是否已經更新,這可能會致使加載文件不是服務器端最新的內容,那咱們如何獲知服務器端內容是否已經發生了更新呢?此時咱們須要用到協商緩存策略。
協商緩存:用戶發送的請求,發送到服務器後,由服務器斷定是否從緩存中獲取資源
- 協商緩存生效,返回304和Not Modified
- 協商緩存失效,返回200和請求結果
協商緩存能夠經過設置兩種 HTTP Header 實現:Last-Modified 和 ETag 。
二者的區別:從名字就能夠看出,強緩存不與服務器交互,而協商緩存則須要與服務器交互。
若是什麼緩存策略都沒設置,那麼瀏覽器會怎麼處理?
對於這種狀況,瀏覽器會採用一個啓發式的算法,一般會取響應頭中的 Date 減去 Last-Modified 值的 10% 做爲緩存時間。
https://www.jianshu.com/p/54cc04190252
52.請求頭header
HTTP請求中的referrer和referrer-policy :http://www.javashuo.com/article/p-kpqqsspu-t.html
53.JS中對象和函數的關係
首先什麼是對象?根據W3C上面的解釋JS中全部事物都是對象,對象是擁有屬性和方法的數據,由此能夠看出基本值類型不是對象(number、string、Boolean、undefined、null),剩下的引用類型(函數、數組...)都是對象,也有人說對象是若干屬性的集合。
函數和對象是什麼關係?
1.函數是一種對象。很明顯函數是一種對象,但你不能說函數是對象的一種。由於他倆之間是沒有包含關係的。
function test() {};
console.log(test instanceof Object); // true
二、對象都是經過函數建立的
先來看一個例子
function test() {
this.name="哈哈"
};
var test2=new test();
console.log(test2 instanceof Object); //true
這個例子能夠說明對象能夠被函數建立。那爲何要說對象都是經過函數建立的,那對象字面量是否是也是經過函數來建立的,答案是確定的,這是一種語法糖方式。舉個簡單的例子
var obj={
name:"哈哈",
age:"18"
}
var obj=new Object()
obj.name="哈哈";
obj.age="18";
上面的對象字面量實際上是經過下面的構造函數來建立的。而其中的Object是一種函數:
console.log(typeof Object) //function
經過上面的簡單例子咱們能夠得出一個結論:對象是經過函數建立的,而函數又是一種對象。那麼這是爲何呢?這就牽扯到prototype原型
54.null 和 undefeated 的區別?
null是一個表示"無"的對象,轉爲數值時爲0;undefined是一個表示"無"的原始值,轉爲數值時爲NaN
http://www.javashuo.com/article/p-puklnbrk-gm.html
55.es6 class
ES6 的 class 屬於一種「語法糖」,因此只是寫法更加優雅,更加像面對對象的編程,其思想和 ES5 是一致的
//定義類
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}
等同於
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return '(' + this.x + ', ' + this.y + ')';
};
var p = new Point(1, 2);
其中 constructor 方法是類的構造函數,是一個默認方法,經過 new 命令建立對象實例時,class必需要用new命令建立,否則會報錯(TypeError: Class constructor Foo cannot be invoked without ‘new’),自動調用該方法。一個類必須有 constructor 方法,若是沒有顯式定義,一個默認的 consructor 方法會被默認添加。因此即便你沒有添加構造函數,也是會有一個默認的構造函數的。通常 constructor 方法返回實例對象 this ,可是也能夠指定 constructor 方法返回一個全新的對象,讓返回的實例對象不是該類的實例。
class繼承中,子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類本身的this對象,必須先經過父類的構造函數完成塑造,獲得與父類一樣的實例屬性和方法,而後再對其進行加工,加上子類本身的實例屬性和方法。若是不調用super方法,子類就得不到this對象。
super 這個關鍵字,既能夠當作函數使用,也能夠當作對象使用。這兩種狀況下,它的用法徹底不用。
1.看成函數使用
class A {}
class B extends A {
constructor() {
super(); // ES6 要求,子類的構造函數必須執行一次 super 函數,不然會報錯。
}
}
注:在 constructor 中必須調用 super 方法,由於子類沒有本身的 this 對象,而是繼承父類的 this 對象,而後對其進行加工,而 super 就表明了父類的構造函數。super 雖然表明了父類 A 的構造函數,可是返回的是子類 B 的實例,即 super 內部的 this 指的是 B,所以 super() 在這裏至關於 ```A.prototype.constructor.call(this, props)``。
class A {
constructor() {
console.log(new.target.name); // new.target 指向當前正在執行的函數
}
}
class B extends A {
constructor {
super();
}
}
new A(); // A
new B(); // B
能夠看到,在 super() 執行時,它指向的是 子類 B 的構造函數,而不是父類 A 的構造函數。也就是說,super() 內部的 this 指向的是 B
2.看成對象使用
在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。
class A {
c() {
return 2;
}
}
class B extends A {
constructor() {
super();
console.log(super.c()); // 2
}
}
let b = new B();
上面代碼中,子類 B 當中的 super.c(),就是將 super 看成一個對象使用。這時,super 在普通方法之中,指向 A.prototype,因此 super.c() 就至關於 A.prototype.c()。
經過 super 調用父類的方法時,super 會綁定子類的 this
class A {
constructor {
this.x = 1;
}
s() {
console.log(this.x);
}
}
class B extends A {
constructor {
super();
this.x = 2;
}
m() {
super.s();
}
}
let b = new B();
b.m(); // 2
上面代碼中,super.s() 雖然調用的是 A.prototytpe.s(),可是 A.prototytpe.s()會綁定子類 B 的 this,致使輸出的是 2,而不是 1。也就是說,實際上執行的是 super.s.call(this)
因爲綁定子類的 this,因此若是經過 super 對某個屬性賦值,這時 super 就是 this,賦值的屬性會變成子類實例的屬性
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3;
console.log(super.x); // undefined
console.log(this.x); // 3
}
}
let b = new B();
上面代碼中,super.x 賦值爲 3,這時等同於對 this.x 賦值爲 3。而當讀取 super.x 的時候,調用的是 A.prototype.x,但並無 x 方法,因此返回 undefined。
注意,使用 super 的時候,必須顯式指定是做爲函數,仍是做爲對象使用,不然會報錯。
class A {}
class B extends A {
constructor() {
super();
console.log(super); // 報錯
}
}
上面代碼中,console.log(super); 的當中的 super,沒法看出是做爲函數使用,仍是做爲對象使用,因此 JavaScript 引擎解析代碼的時候就會報錯。這是,若是能清晰的代表 super 的數據類型,就不會報錯。
最後,因爲對象老是繼承其餘對象的,因此能夠在任意一個對象中,使用 super 關鍵字
https://blog.csdn.net/a419419/article/details/82772412
56.JS的運行機制?
https://baijiahao.baidu.com/s?id=1615713540466951098&wfr=spider&for=pc
57.函數的防抖和節流
https://www.jianshu.com/p/c8b86b09daf0
58.javascript判斷一個字符串或者數組裏面出現最多的元素及其出現的次數
字符串:
var str = 'aabbccccdddd';
var obj = {};
for (var i = 0; i < str.length; i++) {
if (!obj[str.charAt(i)]) {
obj[str.charAt(i)] = 1;
} else {
obj[str.charAt(i)]++;
}
}
console.log(obj);
var maxVal = 0;
var maxStr = '';
for (var j in obj) {
if (obj[j] > maxVal) {
maxVal = obj[j];
maxStr = j;
}
}
console.log('最多的是:' + maxStr + ',出現了:' + maxVal + '次');
數組:
var arr = [1, 2, 3, 4, 1, 2, 2, 2, 2, 4];
var obj = {};
for (var i = 0; i < arr.length; i++) {
if (!obj[arr[i]]) {
obj[arr[i]] = 1;
} else {
obj[arr[i]]++;
}
}
var maxVal = 0;
var maxStr = '';
for (var j in obj) {
if (obj[j] > maxVal) {
maxVal = obj[j];
maxStr = j;
}
}
console.log('最多的是:' + maxStr + ',出現了:' + maxVal + '次');
https://blog.csdn.net/m0_37273490/article/details/80712466
59.獲取數組最大值?
var arr = [1,4,2,0,-2,5];
var max = Math.max.apply(null, arr);
var max = Math.max(...arr);
var max = arr.sort().reverse()[0];
var max = arr.sort(function (a, b) {
return b - a;
})[0];
60.HTTP協議
當咱們在瀏覽器地址欄上輸入要訪問的URL後,瀏覽器會分析出URL上面的域名,而後經過DNS服務器查詢出域名映射的IP地址,瀏覽器根據查詢到的IP地址與Web服務器進行通訊,而通訊的協議就是HTTP協議。
https://blog.csdn.net/aliujiujiang/article/details/81088317
61.DNS服務
一般咱們訪問一個網站,使用的是主機名或者域名來進行訪問的。由於相對於IP地址(一組純數字),域名更容易讓人記住。但TCP/IP協議使用的是IP地址進行訪問的,因此必須有個機制或服務把域名轉換成IP地址。DNS服務就是用來解決這個問題的,它提供域名到IP地址之間的解析服務。
![](http://static.javashuo.com/static/loading.gif)
62.HTTP與TCP/IP、DNS的關係
HTTP協議與它們之間的關係:
![](http://static.javashuo.com/static/loading.gif)
HTTP與TCP/IP、DNS的關係
當客戶端訪問Web站點時,首先會經過DNS服務查詢到域名的IP地址。而後瀏覽器生成HTTP請求,並經過TCP/IP協議發送給Web服務器。Web服務器接收到請求後會根據請求生成響應內容,並經過TCP/IP協議返回給客戶端。
63.箭頭函數
引入箭頭函數有兩個方面的做用:更簡短的函數而且不綁定this
。
箭頭函數表達式的語法比函數表達式更簡潔,而且沒有本身的this,arguments,super或 new.target。
這些函數表達式更適用於那些原本須要匿名函數的地方,而且它們不能用做構造函數。
箭頭函數不會建立本身的this,它只會從本身的做用域鏈的上一層繼承this
。
箭頭函數沒有prototype屬性。
因爲 箭頭函數沒有本身的this指針,經過 call()
或 apply()
方法調用一個函數時,只能傳遞參數(不能綁定this),他們的第一個參數會被忽略。(這種現象對於bind方法一樣成立)
不斷完善...