面試總結JavaScript篇

此文主旨是記錄面試中遇到的面試題,包括js中常見,易錯,重要知識點

window.onload和$(document).ready()的區別

window.onload是在頁面中包含圖片在內的全部元素所有加載完成再執行;
$(document).ready()是DOM樹加載完成以後執行,不包含圖片,其餘媒體文件;
所以$(document).ready()快於window.onload執行;

數組去重

const arr = ['a','bb','22','a','yuci','haha','22'];

1.es6數據結構Setjavascript

let unique = new Set(arr);  
console.log(Array.from(unique));

2.使用push()html

let arr2 = [];  
for(let i = 0; i < arr.length; i++) {  
    if(arr2.indexOf(arr[i]) == -1) { //不包含某個值則返回-1  
        arr2.push(arr[i]);  
    }  
}  
console.log(arr2);
//若是當前數組的第i項在當前數組中第一次出現的位置不是i,那麼表示第i項是重複的,忽略掉。不然存入結果數組  
let arr3 = [arr[0]];  
for(let i = 1; i < arr.length; i++) {  
    if(arr.indexOf(arr[i]) == i) {  
        arr3.push(arr[i]);  
    }  
}  
console.log(arr3);

3.排序去除相鄰重複元素java

let arrSort = arr.sort();  
let arr4 = [];  
for(let i = 0; i< arrSort.length; i++) {  
    if(arrSort[i] != arrSort[i+1]) {  
        arr4.push(arrSort[i]);  
    }  
}  
console.log(arr4);

4.使用splice()node

let len = arr.length;  
for(let i = 0; i < len; i++) {  
    for(let j = i + 1; j < len; j++) {  
        if(arr[i] === arr[j]) {  
            arr.splice(i,1);  
            len--;  
            j--;  
        }  
    }  
}  
console.log(arr);

事件委託

得益於事件冒泡,當多個元素有相同的事件,將事件綁定在父元素git

var oUl = document.getElementById('oul');  
oUl.addEventListener('click', function(e) {  
    var e = e||window.event;  
    var tar = e.target;  
    if(tar.nodeName === 'LI') {  
        alert(tar.innerHTML);  
    }  
})

更詳細請看:事件委託es6

判斷變量類型

  • typeof()用於判斷簡單數據;
  • 判斷一個變量是對象仍是數組使用instanceof,constructor或Object.prototype.toString.call();

更詳細請看:判斷數據類型github

同步和異步(簡要闡述)

同步:因爲js單線程,同步任務都在主線程上排隊執行,前面任務沒執行完成,後面的任務會一直等待;

異步:不進入主線程,進入任務隊列,等待主線程任務執行完成,開始執行。最基礎的異步操做setTimeout和setInterval,等待主線程任務執行完,在開始執行裏面的函數;

更詳細請看:js運行機制面試

返回false的幾種狀況

false,null,0,「」,undefined,NaN數組

js類型值的區別

存儲地:

簡單數據類型:存儲在棧中;

引用數據類型:存儲在堆中,在棧中存儲了指針,指向存儲在堆中的地址,解釋器會先檢索在棧中的地址,從堆中得到實體;

大小:

簡單數據類型:大小固定,佔用空間小,頻繁使用,因此存儲在棧中;

引用數據類型:大小不固定,佔用空間大;

閉包

何爲閉包:有權訪問另外一個做用域中變量的函數

閉包特性:可實現函數外訪問函數內變量,外層變量能夠不被垃圾回收機制回收

爲何?怎麼解決?
for(var i = 0; i < 10; i++) {  
    setTimeout(function() {  
        console.log(i);    
    }, 1000);  
}

輸出結果都爲10,由於for()循環過程當中每次傳值,匿名函數並無執行,至關於執行10次function(){console.log(i);},循環結束i變爲10,因此輸出所有爲10;瀏覽器

使用閉包,自執行匿名函數包裹:

for(var i = 0; i < 10; i++) {  
    (function(j) {  
        setTimeout(function() {  
            console.log(j);    
        }, 1000);  
    })(i);  
}

外部匿名函數當即執行,把 i 做爲參數,賦值給 j ,由於是當即執行,因此每次循環輸出不一樣值。

引用外層變量不被回收,會相比其餘函數佔用更高內存,使用不當容易形成內存泄漏。

this的指向

全局範圍:指向window(嚴格模式下不存在全局變量,指向undefined);

普通函數調用:指向window;

對象方法調用:指向最後調用它的對象;

構造函數調用:指向new出來的對象;

顯示設置this:call,apply方法顯示將this指向第一個參數指明的對象

new具體作了些什麼

建立一個新對象foo;

並將它的__proto__指向其構造函數的prototype,foo.__proto__ = Foo.prototype;

動態將this指向新對象,Foo.apply(foo,arguments);

執行函數體中的代碼;

放回新對象foo;

原型和原型鏈

建立一個函數就會爲其建立一個prototype屬性,指向這個函數的原型對象,原型對象會自動得到constructor屬性,指向prototype屬性所在函數。

Function.prototype.a = "a";    
Object.prototype.b = "b";    
function Person(){}    
console.log(Person);    //function Person()    
let p = new Person();    
console.log(p);         //Person {} 對象    
console.log(p.a);       //undefined    
console.log(p.b);       //b
p.__proto__ === Person.prototype;Person.prototype.constructor === Person

當調用某種方法或查找某種屬性時,首先會在自身調用和查找,若是自身並無該屬性或方法,則會去它的__proto__屬性中調用查找,也就是它構造函數的prototype中調用查找,若是構造函數中也沒有該屬性方法,則會去構造函數的隱式原型中查找,一直到null,就這樣造成原型鏈。

更多有關原型請看:原型和原型鏈

繼承方式

原型鏈繼承:

Child()的原型做爲Parent()的實例來繼承Parent()的方法屬性

由於全部實例都繼承原型方法屬性,其中一個實例對原型屬性值更改後,全部實例調用該屬性的值所有更改

function Parent() {}  
Parent.prototype.parentSay = function() {  
    return 'i am parent';  
}  
function Child() {}  
Child.prototype.childSay = function() {  
    return 'i am child';  
}  
Child.prototype = new Parent();  
var par = new Parent();  
var kid = new Child();  
  
console.log(kid.parentSay());           //i am parent

構造函數繼承:

在子類的構造函數內部經過call或apply來調用父類構造函數

沒法實現函數的複用

function People() {  
    this.name = ['zhangsan','lisi','wangwu'];  
}  
function Person() {  
    People.call(this);  
}  
var per1 = new Person();  
per1.name.push('zhanliu');  
console.log(per1.name);     //["zhangsan", "lisi", "wangwu", "zhanliu"]  
  
var per2 = new Person();  
console.log(per2.name);     //["zhangsan", "lisi", "wangwu"]

組合繼承:

將原型鏈繼承和構造函數繼承結合,最經常使用的繼承模式

原型鏈繼承共享的屬性和方法,構造函數繼承實例屬性

function People(num) {  
    this.num = num;  
    this.name = ['zhangsan','lisi','wangwu'];  
}  
People.prototype.numCount = function() {  
    console.log(this.num);  
}  
function Person(num) {  
    People.call(this, num);  
}  
//繼承方式  
Person.prototype = new People();  
Person.prototype.constructor = Person;  
  
var per1 = new Person(10);  
per1.name.push('zhaoliu');  
console.log(per1.name);     //["zhangsan", "lisi", "wangwu", "zhanliu"]  
per1.numCount();            //10  
  
var per2 = new Person(20);  
console.log(per2.name);     //["zhangsan", "lisi", "wangwu"]  
per2.numCount();            //20

更多繼承方式請看:繼承方式

數組經常使用方法

改變原數組:

尾部刪除pop(),尾部添加push(),頭部刪除shift(),頭部添加unshift(),排序sort(),顛倒數組元素reverse(),刪除或插入元素splice();

不會改變元素組:

合併數組concat(),拼接數組元素join(),截取元素slice(),indexOf(),lastIndexOf(),toString()

更詳細數組方法總結請看:Array數組方法總結

數據存儲

Cookie:用於客戶端與服務端通訊,也具備本地存儲的功能

localStorage,sessionStorage:專門用於存儲

區別:

大小:Cookie容量爲4K,由於用於客戶端與服務端通訊,全部http都攜帶,若是太大會下降效率; localStorage,sessionStorage大小爲5M。

失效時間:Cookie會在瀏覽器關閉時刪除,除非主動設置刪除時間;localStorage一直都在直到用戶主動刪除或清除瀏覽器緩存;sessionStorage在瀏覽器關閉時刪除。

結束語:

若有錯誤,歡迎指正

相關文章
相關標籤/搜索