Js 經典面試題

Jason_++發表於2020-11-07

Js 經典面試題

原型與原型鏈

原型是一個物件,用於實現物件的屬性繼承,可以理解為物件的父親,一個函式的原型的原型A.prototype為constructor
每個物件都有一個_proto_指向他的原型
原型鏈是由原型物件組成,每個物件都_proto_屬性,指向了建立該物件的建構函式的原型,_proto_將物件連線起來組成了原型鏈。是一個用來實現繼承共享屬性的有限的物件鏈。
屬性查詢機制: 當查詢物件的屬性時,如果例項物件自身不存在該屬性,則沿著原型鏈往上一級查詢,找到時則輸出,不存在時,則繼續沿著原型鏈往上一級查詢,直至最頂級的原型物件Object.prototype,如還是沒找到,則輸出 undefined;
屬性修改機制: 只會修改例項物件本身的屬性,如果不存在,則進行新增該屬性,如果需要修改原型的屬性時,則可以用: b.prototype.x = 2;但是這樣會造成所有繼承於該物件的例項的屬性發生改變。
在這裡插入圖片描述
判斷陣列和物件Array.isArray()

扁平化把一個二維陣列轉變成一維陣列

Flat()方法會移除陣列的空項

let arr = [1,2,[3,4],[5,6]];
console.log(arr.flat());//方法會移除陣列中的空項
//方式二
function Flat(arr){
	var str = arr.toString();//把arr變成一個字串
	return JSON.parse("["+str+"]");//然後轉換成物件
}
console.log(Flat(arr));

//方式三 es6打散
Let brr = [].concat(...arr);//es6打散在合併
console.log(brr);

深拷貝淺拷貝

淺拷貝只拷貝一層,拷貝的是引用,當原資料發生改變時,拷貝物件也會發生改變新舊物件還是共享同一塊記憶體。
Es6淺拷貝 object.desing
深拷貝拷貝了多層,新物件跟原物件不共享記憶體,修改新物件不會改到原物件。
Es6深拷貝缺陷 Json.parse(json.stringify())
缺陷:如果obj裡面有時間物件 時間將只是字串的形式,而不是物件的形式

//遞迴方式 實現深拷貝
Function deepCody(obj){
	If(Arrey.isArrey(obj)){
			Var newObj= []
	}else{
		Var newobj = {}
	}
 
For(var I in obj){
	If(typeof  obj[I] == 'object'){
			Newobj[i] ==deepCopy(obj[i])
		}else{
			Newobj[i] ==obj[i]
		}
	}
	Retrue newobj
}
       var obj1 = {
           a:[1],
           b:2
       }
 
       var obj2 = deepCopy(obj1);
       obj1.a.push(2);
       console.log(obj2.a[1]);

Ts 與 Js的區別

Ts是js的超級,interfaces 去定義資料的型別
Ts中泛型是一種任意型別,型別是安全的
泛型是指在定義函式、介面或類的時候,不預先指定具體的型別,使用時再去指定型別的一種特性
Ts在開發時就能給出編譯錯誤,而js錯誤需要執行時才會暴露。
作為強型別語言,你可以明確知道資料的型別。程式碼可讀性極強,幾乎每個人都能理解

JS 演算法快排

在這裡插入圖片描述

Event Loop(事件迴圈)

eventLoop 是由JS的宿主環境(瀏覽器)來實現的;

  1. 函式入棧,當Stack中執行到非同步任務的時候,就將他丟給WebAPIs,接著執行同步任務,直到Stack為空;
  2. 此期間WebAPIs完成這個事件,把回撥函式放入佇列中等待執行(微任務放到微任務佇列,巨集任務放到巨集任務佇列)
  3. 執行棧為空時,Event Loop把微任務佇列執行清空;
  4. 微任務佇列清空後,進入巨集任務佇列,取佇列的第一項任務放入Stack(棧)中執行,回到第1步。

微任務:then 、messageChannel 、mutationObersve
巨集任務:setTimeout、setInterval、setTmmediate(只相容ie)
Node 環境中微任務是插縫執行,(如果執行巨集任務的時候發現了微任務, 不會像瀏覽器一樣執行了,而是將為微任務放到微任務佇列中,等待整個巨集 任務佇列執行完畢或者達到執行上線後,下一個階段開始的時候先執行 完微任務佇列中的任務

this指向問題:

1、普通模式 普通函式
誰呼叫這個方法,this就指向誰,沒有呼叫物件時,this則指向window
2、嚴格模式 普通函式
誰呼叫這個方法,this就指向誰,沒有呼叫物件時,結果為undefined
3、普通模式 箭頭函式
箭頭函式中this指向箭頭函式所在環境的this
建構函式的this指向例項
改變this指向的三個方法:call apply bind
## call、apply和bind的區別:
apply、call用法一樣,只是接收引數的方式不一樣
call 需要把引數按順序傳遞進去,而 apply 則是把引數放到陣列裡。
bind()方法會建立一個新函式,稱為繫結函式,當呼叫這個繫結函式時,
繫結函式會以建立它時傳入 bind()方法的第一個引數作為 this,
傳入 bind() 方法的第二個以及以後的引數加上繫結函式執行時本身的引數按照順序作為原函式的引數來呼叫原函式。 
實現繼承是通過原型鏈
只有函式物件有原型屬性,這個屬性值又是一個物件,
目的:例項共享屬性或者方法
真正實現繼承通過什麼?propo是指標
每個物件都有一個__proto__指向他的原型物件
instanceof原理
能在例項的 原型物件鏈 中找到該建構函式的prototype屬性所指向的 原型物件,就返回true。

setTimeout Promise async/await的區別

setTimeout
是非同步執行函式 , 當js主執行緒執行到此函式時,不會等待settimeout中的回撥函式 ,會直接進行settimeout下面的語句(儘管setTimeout的延遲時間為0時) 當執行完當前事件迴圈的時候,settimeout中的回撥會在下次(或者某一個)事件迴圈中被執行
Promise
本身是同步的立即執行函式,當在執行體中執行resolve()或者reject的時候,此時是非同步操作
會先執行then/catch(非同步執行)等,等主棧完成後,才會去執行resolve()/reject中的方法,
async await
async函式返回一個promise物件,當函式執行的時候,一旦遇到await就會先返回,等到觸發的非同步操作完成(await的函式),在執行函式體後面的語句,可以理解為,async讓出了執行緒,跳出了async函式體,因此await函式後的語句相當於在then回撥中執行.
await的含義為等待,也就是 async 函式需要等待await後的函式執行完成並且有了返回結(Promise物件)之後,才能繼續執行下面的程式碼。await通過返回一個Promise物件來實現同步的效果。
function() yeild 非同步請求*

跨域問題

jsonP:通過動態建立script,再請求一個帶參網址實現跨域通訊。//json補白
缺點:只能用get請求,不能用post請求
不能很容易的確定知否請求失敗,因為不能註冊success、error等事件監聽
安全性較低,是因為他是從其他域中載入程式碼執行,容易受到跨站請求偽造的攻擊
跨域資源共享 cors
伺服器代理 axios

閉包

特點:函式外部可以訪問函式內部變數的函式
缺點:記憶體洩漏

//釋放一個簡單的閉包
	function Bibao(){
		return function (){
			console.log("Hello");
		}
	}
	var a = Bibao();//通過一個變數

暫時性死區

Let a = 5iftrue{
console.lon(a)//報錯
Let a = 20}

原生請求 get與post

提交引數不一樣,get請求在網址後面拼接引數 (?id=2&name=‘jack’)
Post:要寫在send裡面post請求必須在send之前,設定請求頭xhr.send(‘username=周林林’)

防抖與節流

防抖:當你不停的觸發一個事件,等到你完全停止後在才會執行
應用場景:比如搜尋框,當使用者不停的輸入內容,此時不傳送Ajax請求,等使用者停止後(300ms)才傳送
節流:當持續觸發事件時,在一定時間內,該事件會執行一次
應用場景:計算滑鼠移動的距離

Js的本地物件,內建物件和宿主物件

本地物件:object、function 、 Array
內建物件:Global Math
宿主物件:Bom Dom

封裝一個promise 請求ajax

pending(進行中)、resolved(完成(成功))、rejected(失敗)

function ajax(url, data, type = "GET") {
 return newPromise((resolve, reject) => {
   let promise;
    if (type == "GET") {
      promise = axios.get(url, { params: data });
    } else {
     promise = axios.post(url, data);
    }
  promise.then((res) => {
     resolve(res.data);
  }).catch((err) => {
     message.error(err);
  })
});
}

ajax封裝

function ajax(url,fn){
    var xhr=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject('Microsoft.XMLHTTP')
    xhr.open('get',url)
    xhr.send()
    xhr.onreadystatechange=function(){
        if(xhr.readyState==4) { //4表示反應就緒
           if(xhr.status==200){
               var data=xhr.responseText
                fn(data)
           }
        }
    }
}

Es6新增:

**indexof()**去某個元素在陣列中的索引,沒有返回-1
**map()**遍歷,有返回值,改變原始陣列,返回新陣列
**forEach()**遍歷陣列,無返回值,不改變原陣列,僅僅只是遍歷,
filter(),過濾出滿足條件的陣列元素,返回一個新陣列,不改變原陣列
**some()**遍歷陣列每一項,只要有一個元素滿足條件就返回true,做刪除用,不改變原陣列。
**every()**遍歷陣列每一項,每一項返回true,最終結果為true.有一項返回false,停止遍歷,結果返回為false。不改變原陣列。
物件/陣列的結構賦值
var 宣告一個變數,有function才有作用域,有宣告提升
let 有塊級作用域,{}是作用域
不存在宣告提升
不允許重複宣告,會報錯
用let宣告,不能看作window的屬性
const 宣告常量,常量的值不允許被改變

設計模式

//單例模式:保證一個類只有一個例項,並且提供一個訪問它的全域性訪問介面

 (function () {//無名函式
 
        var _instance = null;//表示例項,預設為空
 
        function Foo() {//建構函式
            this.prop1 = "例項屬性1";
            this.prop2 = "例項屬性2";
        }
 
        return {//返回一個物件,在物件裡寫一個方法活得不例項
            getInstance: function () {
                //為了保證只有有個例項,如果有就用原來的,如果沒有就new一個新的例項
                if (!_instance) {
                    _instance = new Foo();
                }`在這裡插入程式碼片`
                return _instance();
            }
        }
    })();

工廠模式
解決集中例項化程式碼的問題,減少程式碼冗餘
缺點:認不清是那一種物件,它會把所有的都當成Object物件
建構函式
即解決了重複例項化程式碼問題,又能分清誰是誰的物件

ajax請求時,如何解析json資料

答案:使用JSON.parse

Javascript的事件流模型都有什麼?

“事件冒泡”:事件開始由最具體的元素接受,然後逐級向上傳播
“事件捕捉”:事件由最不具體的節點先接收,然後逐級向下,一直到最具體“DOM事件流”:三個階段:事件捕捉,目標階段,事件冒泡

MCM模式
在這裡插入圖片描述
MVVM模式
在這裡插入圖片描述

相關文章