天天看點

前端面試題(javascrip)

每天持續更新5到8題

1、javascrip的值類型和引用類型;分别typeof傳回什麼類型?

(1)值類型(基本類型):字元串(string)、數值(number)、布爾值(boolean)、undefined、null ;ex6新增了易種基本資料類型symbol(唯一辨別)。

(2)引用類型:對象(Object)、數組(Array)、函數(Function)

// 利用typeof來區分
typeof 'abc' // string
typeof 123 // number
typeof true // boolean
typeof undefined // undefined
typeof null // object
// typeof 區分不出來引用類型(除了函數)
typeof {} // object
typeof [] // object
typeof console.log //function
           

2、split() 和 join() 的差別

split與join函數通常都是對字元或字元串的操作。

差別:

join() 方法用于把數組中的所有元素放入一個字元串。元素是通過指定的分隔符進行分隔的。join()預設分隔符為逗号。

<script>
   var a=new Array();
    a[0]="XHTML";
    a[1]="CSS";
    a[2]="JavaScript";
    alert(a.join("#")); //XHTML#css#JavaScript
</script>
           

split()用于分割字元串,傳回一個數組,split()隻有一個參數時:分割的字元串或正規表達式;兩個參數時,第二個參數是指傳回的數組中元素的個數。

var string=“hello world?name=xiaobai”;

var splitString = string.split("?");

console.log(splitString);//["hello world","name=xiaobai"]
           

3、數組方法:pop(), push(), unshift(), shift()

push() 方法可以在數組的末屬添加一個或多個元素

pop() 方法把數組中的最後一個元素删除

shift() 方法把數組中的第一個元素删除

unshift() 方法可以在數組的前端添加一個或多個元素

實作類似棧的行為:将push() 和pop() 結合在一起

前端面試題(javascrip)

實作類似隊列的行為:将shift()和push()方法結合在一起,在數組的後端添加項,從數組的前端移除項:

前端面試題(javascrip)

4、事件綁定和普通事件有什麼差別?

普通添加事件的方法:

var btn = document.getElementById("hello");
btn.onclick = function(){
	alert(1);
}
btn.onclick = function(){
	alert(2);
}
//隻會執行alert2
           

事件綁定方式添加事件:

var btn = document.getElementById("hello");
btn.addEventListener("click",function(){
	alert(1);
},false);
btn.addEventListener("click",function(){
	alert(2);
},false);
//執行上面的代碼會先alert 1 再 alert 2
           

總結:普通添加事件的方法不支援添加多個事件,最下面的事件會覆寫上面的,而事件綁定(addEventListener)方式添加事件可以添加多個。

5、IE和DOM事件流的差別?

IE和DOM事件流的差別主要有四個方面不一樣

  • 執行的順序不一樣
<body>
   <div>
     <button id = 'btn'>點選<button>
   </div>
<body>
           

三種事件流分别是:

冒泡型事件模型(IE事件流): button->div->body

捕獲型事件模型(Netscape事件流): body->div->button

DOM事件模型: body->div->button->button->div->body (先捕獲後冒泡)

-IE和DOM事件偵聽函數的差別

IE使用: 
[Object].attachEvent("name_of_event_handler", fnHandler); //綁定函數 
[Object].detachEvent("name_of_event_handler", fnHandler); //移除綁定 
           
DOM使用: 
[Object].addEventListener("name_of_event", fnHandler, bCapture); //綁定函數 
[Object].removeEventListener("name_of_event", fnHandler, bCapture); //移除綁定 
           
  • 事件參數不一樣和this指向不一樣

attachEvent接受兩個參數,第一個參數是事件名稱,第二個fnHandler是回調處理函數

注意:IE下利用attachEvent注冊的處理函數調用時,this指向不再是先前注冊事件的元素,這時的this為window對象了

IE9以後就和DOM事件流是一樣的

addEventListener方法接受三個參數:

第一個參數是事件名稱,值得注意的是,這裡事件名稱與IE的不同,事件名稱是沒’on’開頭的;

第二個參數fnHandler是回調處理函數;

第三個參數注明該處理回調函數是在事件傳遞過程中的捕獲階段被調用還是冒泡階段被調用

注意:它可以在一個DOM元素上綁定多個事件處理器,并且在處理函數内部,this關鍵字仍然指向被綁定的DOM元素,另外處理函數參數清單的第一個位置傳遞事件event對象
           

6、call 和 apply 的差別?

相同點:

1.call() 和 apply() 都可可以用來代替另一個對象調用一個方法,将一個函數的對象上下文從初始的上下文改變為由thisObj指定的新對象

2.兩個方法都可以指定調用實參。

差別:

call() 和 apply() 的基本差別:apply和call的功能是一樣的,隻是傳入的參數清單形式不同。

call(): 它可以接受多個參數,第一個參數與apply一樣,後面則是一串參數清單。

apply():最多隻能有兩個參數——新this對象和一個數組argArray。

apply:調用一個對象的一個方法,用另一個對象替換目前對象。例如:B.apply(A, arguments);即A對象應用B對象的方法。
call:調用一個對象的一個方法,用另一個對象替換目前對象。例如:B.call(A, args1,args2);即A對象調用B對象的方法。
var someObject = {
    myProperty:'Foo',
    myMethod:function (prefix,posfix) {
        console.log(prefix + this.myProperty + posfix);
    }
};
someObject.myMethod('<','>');//<Foo>

var someOtherObject = {
    myProperty:'Bar'
};
someObject.myMethod.call(someOtherObject,'<','>');//<Bar>
someObject.myMethod.apply(someOtherObject,['<','>']);//<Bar>
           

7、javascrip this指針,閉包,作用域

this指針

在函數執行時,this 總是指向調用該函數的對象。要判斷 this 的指向,其實就是判斷 this 所在的函數屬于誰。

  1. 有對象就指向調用對象
  2. 沒調用對象就指向全局對象
  3. 用new構造就指向新對象
  4. 用apply 或 call 或 bind 來改變this的指向
// apply 和 call 調用以及 bind 綁定: 指向綁定的對象
        // apply() 方法接受兩個參數第一個是函數運作的作用域, 另外一個是一個參數數組(arguments)。
        // call() 方法第一個參數的意義與 apply() 方法相同, 隻是其他的參數需要一個個列舉出來。
        // 簡單來說, call 的方式更接近我們平時調用函數, 而 apply 需要我們傳遞 Array 形式的數組給它。 它們是可以互相轉換的。
        var myObject = { value: 100 };
        var foo = function() {
            console.log(this);
        };
        foo(); // 全局變量 global
        foo.apply(myObject); // { value: 100 }
        foo.call(myObject); // { value: 100 }
        var newFoo = foo.bind(myObject);
        newFoo(); // { value: 100 }</span>
           

作用域

定義一個函數就開辟了一個局部作用域,整個js執行環境就是一個全局作用域。

閉包

閉包是有權通路另一個函數作用域中的變量的函數,實質上是将函數内部與外部連接配接起來的橋梁。

閉包的特點:

1、函數套函數;

2、内部函數有權通路外部函數的變量;

3、參數和變量不會被垃圾回收機制收回。

閉包常見的用途:

一:是使外部函數可以突破作用域進而通路定義在内部函數中的變量。

二:是讓變量的值始終儲存在記憶體中。

三:用來子產品化代碼(類塊級作用域)。

優點:

1、可以将一個變量長期駐紮在記憶體中;

2、避免全局變量的污染;

3、私有成員的存在。

缺點:

記憶體消耗極大,導緻記憶體洩漏。

function F1(){
            let a = 100; 
            return function f2(){  // 閉包的特點:1. 函數套函數
                console.log(a)  // 2. 内部函數可以引用外部變量
            }
        }
        let f1 = F1();
        let a = 200 ;  // 重新定義變量來看看調用時走哪個
        f1();  // 100  函數調用時的變量是建立時候的變量而不是調用時的變量

           

8、什麼是事件委托?

符合w3c的事件綁定:addEventLisntener / attachEvent

就是利用事件冒泡原理,讓自己的所觸發的事件,讓父元素代替執行。

9、添加、删除、替換、插入某個節點的方法?

添加:obj.appendChild();

删除:obj.removeChild();

替換:obj.replaceChild();

插入:obj.insetBefore().

10、編寫一個數組去重的方法

先将原數組排序,在與相鄰的進行比較,如果不同則存入新數組。

function unique2(arr) {
            var formArr = arr.sort() //字元排序
            var newArr=[formArr[0]]
            for (let i = 1; i < formArr.length; i++) {
                if (formArr[i]!==formArr[i-1]) {
                    newArr.push(formArr[i])
                }
            }
            return newArr
            
        }
        console.log(unique2([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]));
        // 結果是[1, 2, 3,  4,5, 6, 7]
           

先将原數組排序,在與相鄰的進行比較,如果不同則存入新數組。

10、下面代碼輸出什麼?

var a;

console.log(typeof ‘a’);

答案:undefined

undefined會在以下三種情況下産生:

  1. 一個變量定義了卻沒有被指派;
  2. 想要擷取一個對象上不存在的屬性或者方法;
  3. 一個數組中沒有被指派的元素

11、已知有字元串foo = “get-element-id”,寫一個函數将其轉化成駝峰式GetElementId

var foo = "get-element-id";
        function combo(msg) {
            var arr = msg.split("-");
            for (var i = 0; i < arr.length; i++) {
                arr[i] = arr[i].charAt(0).toUpperCase() + arr[i].substr(1, arr[i].length - 1)
            }
            msg = arr.join("");
            console.log(msg);
        }
        combo(foo);
           

12、var num=[3,6,2,4,1,5]

(1) 實作對該數組的倒排

function s1() {

            var num = [3, 6, 2, 4, 1, 5],
                arr = [];
            for (var i = num.length - 1; i >= 0; i--) {
                arr.push(num[i]);
            }
            console.log(arr);
        }
        s1();
           

(2)冒泡排序

var foo=[1,3,44,55,64,26,78,98,51,48];
        function sort(arr){
           for(var i=0;i<arr.length;i++){
               for(var j=i+1;j<arr.length;j++){
                   var temple="";
                   if(arr[i]>arr[j]){    //'>'從小到大排序,'<'從大到小排序
                       temple=arr[i];
                       arr[i]=arr[j];
                       arr[j]=temple;
                   }
               }
           }
           return arr;
        }
        console.log(sort(foo));
           

13、下列代碼輸出什麼?

var foo = 1;
        function a(){
            console.log(foo);
            var foo = 2;
            console.log(foo);
        }
        a();
           

輸出undefined 和 2

上面的函數相當于:

var foo = 1;
        function a(){
        	var foo;
            console.log(foo);//undefined
            foo = 2;
            console.log(foo);//2
        }
        a();
           

總結:函數聲明與變量聲明會被javascrip引擎隐式的提升到目前作用域的頂部,但是隻提升名稱,不會提升指派部分。

14、用js實作随機選取10-100的十個數,存入一個數組,并排序。

var foo = [];
        function getRandom(istart,iend){
            var iChoise=iend-istart;
           return Math.floor(Math.random()*iChoise+istart);
        }//取随機數
        function a(){
            for(var i=0;i<10;i++){
                var result = getRandom(10,100);
                foo.push(result);
            }           
            console.log(foo.sort());      
        }
       a();
           

15、js延遲加載的方式有哪些?

  1. defer屬性:表明腳本在執行時不會影響頁面的構造。也就是說,腳本會被延遲到整個頁面都解析完畢之後再執行。
  2. async屬性:不讓頁面等待腳本下載下傳和執行,進而異步加載頁面其他内容。

async和defer一樣,都不會阻塞其他資源下載下傳,是以不會影響頁面的加載。

缺點:不能控制加載的順序

  1. 動态建立DOM方式
  2. 使用jQuery的getScript()方法
$.getScript("outer.js",function(){//回調函數,成功擷取檔案後執行的函數  
     console.log("腳本加載完成")  
});
           
  1. 使用setTimeout延遲方法
  2. 讓JS最後加載

16、判斷一個字元串中出現最多的字元,統計這個次數。

var str = 'sjdhbbbbbbbbbbbbb';
        var json = {}
        var key;
        for (var i = 0; i < str.length; i++) {
            key = str[i];
            if (!json[key]) {
                json[key] = 1;//如果沒有就為1
            } else {
                json[key]++;//如果有,就加1
            }
        }
        var iMax = 0,
            index = '';
        for (var i in json) {
            if (iMax < json[i]) {
                iMax = json[i];
                index = i;
            }
        }
        alert('出現次數最多的是:'+index+',出現了'+iMax+'次');
        
           

17、javascrip中callee 和caller 的作用?

caller是javascript函數類型的一個屬性,它引用調用目前函數的函數。

function func() {
    alert(func.caller);
}

function func1() {
    func();
}

func1();
           

callee則不是函數對象的屬性,它是函數上下文中arguments對象的屬性。

function func() {
    alert(arguments.callee);
}
           

18、斐波那契數列,又稱黃金分割數列,指的是這樣一個數列:1,1,2,3,5,8,13,21……從第3個數字開始,每個數字等于它前面兩個數字之和

function fb(n) {
            var a, b, res;
            a = b = 1;
            if (n == 1 || n == 2) {
                return 1;
            }
            for (var i = 3; i <= n; i++) {
                res = a + b;
                a = b;
                b = res;
            }
            return res;
        }
        alert(fb(8));
           

19、列舉浏覽器對象BOM裡常用的至少4個對象,并列舉Window對象的常用方法至少5個。

對象:window document location screen history

方法:alert() confirm() prompt() open() close()

20、javascrip如何實作繼承

原型鍊繼承

基本思想:利用原型讓一個引用類型繼承另外一個引用類型的屬性和方法。

構造函數,原型,執行個體之間的關系:每個構造函數都有一個原型對象,原型對象包含一個指向構造函數的指針,而執行個體都包含一個指向原型對象的内部指針。

function SuperType() {
this.property = true;
}
SuperType.prototype.getSuperValue = function() {
return this.property;
}
function subType() {
this.property = false;
}
//繼承了SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function (){
return this.property;
}
var instance = new SubType();
console.log(instance.getSuperValue());//true
           

借用構造函數繼承

基本思想:在子類型構造函數的内部調用超類構造函數,通過使用call()和apply()方法可以在新建立的對象上執行構造函數。
function SuperType() {
this.colors = ["red","blue","green"];
}
function SubType() {
SuperType.call(this);//繼承了SuperType
}
var instance1 = new SubType();
instance1.colors.push("black");
console.log(instance1.colors);//"red","blue","green","black"
var instance2 = new SubType();
console.log(instance2.colors);//"red","blue","green"
           

組合繼承

基本思想:将原型鍊和借用構造函數的技術組合在一塊,進而發揮兩者之長的一種繼承模式。
function SuperType(name) {
this.name = name;
this.colors = ["red","blue","green"];
}
SuperType.prototype.sayName = function() {
console.log(this.name);
}
function SubType(name, age) {
SuperType.call(this,name);//繼承屬性
this.age = age;
}
//繼承方法
SubType.prototype = new SuperType();
Subtype.prototype.constructor = Subtype;
Subtype.prototype.sayAge = function() {
console.log(this.age);
}
var instance1 = new SubType("EvanChen",18);
instance1.colors.push("black");
consol.log(instance1.colors);//"red","blue","green","black"
instance1.sayName();//"EvanChen"
instance1.sayAge();//18
var instance2 = new SubType("EvanChen666",20);
console.log(instance2.colors);//"red","blue","green"
instance2.sayName();//"EvanChen666"
instance2.sayAge();//20
           

寄生式繼承

基本思想:建立一個僅用于封裝繼承過程的函數,該函數在内部以某種方式來增強對象,最後再像真正是它做了所有工作一樣傳回對象。
function createAnother(original) {
var clone = object(original);
clone.sayHi = function () {
alert("hi");
};
return clone;
}
var person = {
name:"EvanChen",
friends:["Shelby","Court","Van"];
};
var anotherPerson = createAnother(person);
anotherPerson.sayHi();///"hi"
           

寄生組合式繼承

基本思想:通過借用函數來繼承屬性,通過原型鍊的混成形式來繼承方法
function inheritProperty(subType, superType) {
var prototype = object(superType.prototype);//建立對象
prototype.constructor = subType;//增強對象
subType.prototype = prototype;//指定對象
}
           

21、哪些操作會造成記憶體洩漏

  1. setTimeout的第一個參數使用哪個字元串而非函數的話,會引發記憶體洩漏
  2. 閉包
  3. 控制台日志
  4. 循環(在兩個對象彼此應用且彼此保留時,就會産生一個循環)

22、生成5個不同随機數

思路:5個不同的數字,每生成一個,就和前面所有的數字做比較,如果有相同的,就放棄目前生成的數字。
var num = [];
        for(var i=0;i<5;i++){
            num[i]=Math.floor( Math.random()*9);///範圍是0到9
            for(var j=0;j<i;j++){
                if(num[i]==num[j]){
                    i--;
                }
            }
        }
        console.log(num);
           

23、簡述同步和異步的差別

同步(Sync)發出一個功能調用時,必須一件一件事做,等前一件做完了才能做下一件事。

異步(Async)當一個異步過程調用發出後,調用者在沒有得到結果之前,就可以繼續執行後續操作。

總結來說,同步和異步的差別:請求發出後,是否需要等待結果,才能繼續執行其他操作。

24、深拷貝和淺拷貝的差別?

淺拷貝隻複制指向某個對象的指針,而不複制對象本身,新舊對象還是共享同一塊記憶體。

深拷貝會另外創造一個一模一樣的對象,新對象跟原對象不共享記憶體,修改新對象不會改到原對象。

通俗說:B複制A,A改變,B也跟着改變為淺拷貝;B不改變為深拷貝

淺拷貝 的實作方式:

  1. Object.assign()
注意:當被複制的對象隻有一層的時候,是深拷貝
  1. Array.prototype.concat()
  2. Array.prototype.slice()
Array的slice和concat方法不修改原數組,隻會傳回一個淺複制了原數組中的元素的一個新數組。

深拷貝 的實作方式

  1. JSON.parse(JSON.stringify())
原理: 用JSON.stringify将對象轉成JSON字元串,再用JSON.parse()把字元串解析成對象,一去一來,新的對象産生了,而且對象會開辟新的棧,實作深拷貝。但不能處理函數。
  1. 遞歸方法
  2. 函數庫lodash
  3. jQuery的extend方法

$.extend( [deep ], target, object1 [, objectN ] )

deep表示是否深拷貝,為true為深拷貝,為false,則為淺拷貝

target 為Object類型 目标對象,其他對象的成員屬性将被附加到該對象上。

object1 objectN可選。 Object類型 第一個以及第N個被合并的對象。

let a=[0,1,[2,3],4],
b=$.extend(true,[],a);
a[0]=1;
a[2][0]=1;
console.log(a,b);

//a 輸出  [1,1,[1,3],4]
//b 輸出  [0,1,[2,3],4]
//可以看到,效果與上面方法一樣,隻是需要依賴JQ庫
           

25、寫一個function ,清除字元串前後的空格

function trim(str) {
    if (str && typeof str === "string") {
        return str.replace(/(^\s*)|(\s*)$/g,""); //去除前後空白符
    }
}
           

26、頁面重繪(repaint)和頁面回流(reflow)

css 與 dom 解析完畢後,合并為渲染樹(render tree)

  • 重繪(repaint): 當 render tree中的一些元素需要更新屬性,但這些屬性隻會影響元素的外觀,風格,而不會影響到元素的布局,此類的頁面渲染叫作頁面重繪。
  • 回流(reflow) :當 render tree 中的一部分(或全部)因為元素的規模尺寸、布局、隐藏 等改變而引起的頁面重新渲染。
可以看出,回流必将引起重繪,而重繪不一定會引起回流。

當頁面布局和幾何屬性改變時就需要回流。

下述情況會發生浏覽器回流:DOM 樹發生變化

改善由于 dom 操作産生的回流:

1、不要一個一個改變元素的樣式屬性,直接改變 className,如果動态改變樣式,則使用 cssText。

2、使用 DocumentFragment 進行緩存操作,引發一次回流和重繪;

這個主要用于添加元素的時候,就是先把所有要添加到元素添加到 1 個 div 中(這個 div也是新加的),最後才把這個 div append 到 body 中。

3、使用 display:none 技術,隻引發兩次回流和重繪;

先 display:none 隐藏元素,然後對該元素進行所有的操作,最後再顯示該元素。因對display:none 的元素進行操作不會引起回流、重繪。是以隻要操作隻會有 2 次回流。

4、使用 cloneNode(true or false) 和 replaceChild 技術,引發一次回流和重繪

27、new操作符具體幹了什麼

new操作符應該是進行了四個操作

1,建立一個空的對象 var obj=new Object();

2,讓空對象的原型屬性指向原型鍊,設定原型鍊 obj.proto=Func.prototype;

3,讓構造函數的this指向obj,并執行函數體 var result=Func.call(obj);

4,判斷傳回類型,如果是值就傳回這個obj,如果是引用類型,傳回這個引用對象。

28、子產品化開發怎麼做

首先我們要知道什麼是子產品化開發?

  1. 子產品就是一個有特定功能的檔案,我們可以通過加載這些子產品得到特定的功能
  2. 子產品化開發就是js的功能分離,通過需求引入不同的檔案
  3. 子產品化開發可以使代碼耦合度降低,避免代碼多次在頁面出現,他最大的作用就是重用

子產品開發要遵循的規範

1、 AMD規範也叫異步子產品加載規範,在這個規範下子產品會異步加載,不影響後面語句的執行,我們可以使用define定義子產品,使用require調用子產品

2、CommonJS規範是伺服器端子產品的規範,node.js就采用了這個規範,每個子產品都有一個單獨的作用域,子產品内部的變量無法被其他子產品讀取,除非定義為global的對象和屬性

3、 CMD規範通用子產品定義.CMD是按需加載,一個子產品就是一個檔案

29、如何實作一個簡單的webpack

1、讀取檔案分析子產品依賴

2、對子產品進行解析執行(深度周遊)

3、針對不同的子產品使用相應的loader

4、編譯子產品,生成抽象文法樹AST。

5、循環周遊AST樹,拼接輸出js。

30、實作(5).add(3).minus(2),使其輸出結果為6。鍊式方法

~ function() {
				//麼一個方法執行完,都要傳回Number這個類的執行個體,這樣才可以繼續調用Number類原型中的方法(鍊式寫法)
				function check(n) {
					n = Number(n);//轉換成數值 
					return isNaN(n)? 0 : n;
				}

				function add(n) {
					n = check(n);
					return this + n;
				}

				function minus(n) {
					n = check(n);
					return this - n;
				}
				Number.prototype.add = add;
				Number.prototype.minus = minus;

			}();
			console.log((5).add(3).minus(2))
           

31、 箭頭函數與普通函數的差別是什麼?構造函數可以使用new生成執行個體,那麼箭頭函數可以嗎?

差別:

1、箭頭函數文法上比普通函數更加簡潔(ES6中每一種函數都可以使用形參預設值和剩餘預算符)

2、箭頭函數沒有自己的this,它裡面的this是繼承函數所處上下文中的this,使用call或apply等任何方式都無法改變this指向。

3、箭頭函數中沒有arguments(類數組),隻能給予…ARG擷取傳遞的參數集合(數組)。

4.箭頭函數不能new執行(因為:箭頭函數沒有prototype)

32、字元串大小寫取反

let str = 'adSFSDsdsDSD';
			str = str.replace(/[a-zA-Z]/g, content => {
				//content:每一次正則比對的結果
				//驗證是否為大寫字母,吧字母轉換成大寫之後看之前是否一樣,如果一樣,之前也是大寫的
				return content.toUpperCase() === content ? content.toLowerCase() : content.toUpperCase();
			})
			console.log(str);
           

33、編寫代碼實作圖檔懶加載

34、前端性能優化

(1) 減少http請求次數:CSS Sprites, JS、CSS源碼壓縮、圖檔大小控制合适;網頁Gzip,CDN托管,data緩存 ,圖檔伺服器。

(2) 前端模闆 JS+資料,減少由于HTML标簽導緻的帶寬浪費,前端用變量儲存AJAX請求結果,每次操作本地變量,不用請求,減少請求次數

(3) 用innerHTML代替DOM操作,減少DOM操作次數,優化javascript性能。

(4) 當需要設定的樣式很多時設定className而不是直接操作style。

(5) 少用全局變量、緩存DOM節點查找的結果。減少IO讀取操作。

(6) 避免使用CSS Expression(css表達式)又稱Dynamic properties(動态屬性)。

(7) 圖檔預加載,将樣式表放在頂部,将腳本放在底部 加上時間戳。

(8) 避免在頁面的主體布局中使用table,table要等其中的内容完全下載下傳之後才會顯示出來,顯示比div+css布局慢。

35、函數節流和函數防抖

函數節流:一個函數執行一次後,隻有大于設定的執行周期後才會執行第二次。

  • 有個需要頻繁觸發函數,處于優化性能角度,在規定時間内,隻讓函數觸發的第一次生效,後面的不生效。

函數防抖:一個需要頻繁觸發的函數,在規定的時間内,隻讓最後一次執行,前面的不生效。

36、從一個url位址到網頁渲染完成,發生了什麼?

1、DNS解析:将域名位址解析成ip位址

2、TCP連接配接:TCP三向交握

3、發送請求封包:HTTP協定的通信内容

4、接受響應:響應封包

5、渲染頁面

6、斷開連接配接:TCP四次揮手

37、var 、let、const的差別

前端面試題(javascrip)

38、[‘1’,‘2’,‘3’].map(parseInt)

map()方法傳回元素、序号、數組本身三個參數

39、typeof和instanceof

前端面試題(javascrip)

40、IE和标準下有哪些相容性的寫法

ev =ev||window.event =>擷取觸發事件的對象

var target=ev.srcElement||ev.target =>擷取觸發事件的源對象

document.documentElement.clientWidth||document.body.clientWidth ==>擷取螢幕的寬度

41、阻止冒泡事件和預設事件

e.stopPropagation()

event.canceBubble=true

阻止預設事件

return false;

e.preventDefault()

42、如何檢測數組的資料類型

obj instanceof Array

Object.prototype.toString.call();

43、setTimeout會在js引擎空閑的時候再執行

44、有關字元串的方法。

方法 解析
charAt() 傳回給定位置的那個字元
charCodeAt() 傳回給定位置的字元編碼
concat() 将一個或多個字元串拼接起來,傳回一個新的字元串
slice() 傳回被操作字元串的一個子字元串
substring() 傳回被操作字元串的一個子字元串,不接受負數,負數轉為0
substr() 傳回被操作字元串的一個子字元串,兩個參數分别是起始位置和長度
indexOf() 從一個字元串搜尋指定的子字元串,傳回子字元串的第一個位置(沒有找到傳回-1)
lastindexOf() 從一個字元串搜尋指定的子字元串,傳回子字元串的最後位置(沒有找到傳回-1)
trim() 會建立一個字元串副本,删除前置以及字尾的所有空格
search() 傳回字元串中第一個比對項的索引
replace() 替換

45、有關數組的方法

改變原數組

方法 解析
reverse() 數組翻轉
sort() 排序(a-b升序)(b-a降序)
splice() 傳回剪接的元素數組,原數組變化 ,索引從0開始(第一參數是索引(從0開始),第二是長度,第三是添加新的資料)

不改變原數組

方法 解析
join() 數組轉成字元串(原數組不變)
split() 字元串變數組
slice() 傳回從原數組中指定開始索引(包含)到結束索引(不包含)之間的項組成的新數組,原數組木變 ,索引從0開始
foreach() 用于調用數組的每個元素,并将元素傳遞給回調函數。
concat() 傳回合并後的新數組,原數組沒變
filter() 建立一個新的數組,新數組中的元素是通過檢查指定數組中符合條件的所有元素。(篩選)
map() 傳回一個新數組,數組中的元素為原始數組元素調用函數處理後的值
reduce() 數組的歸并方法,但是reduce() 可同時将前面數組項周遊産生的結果與目前周遊項進行運算
reduceRight() 周遊的順序相反,它是從數組的最後一項開始,向前周遊到第一項。

46、判斷資料類型

方法 解析
typeof 一個操作符,其右側跟一個一進制表達式,并傳回這個表達式的資料類型
instanceof 用來判斷 A 是否為 B 的執行個體
Array.isArray() 用以确認某個對象本身是否為 Array 類型
constructor prototype上添加一個 constructor 屬性,并讓其指向 F 的引用
toString.call() toString() 是 Object 的原型方法,調用該方法,預設傳回目前對象的 [[Class]]

47、柯裡化

// 實作一個add方法,使計算結果能夠滿足如下預期:
add(1)(2)(3) = 6;
add(1, 2, 3)(4) = 10;
add(1)(2)(3)(4)(5) = 15;

function add() {
    // 第一次執行時,定義一個數組專門用來存儲所有的參數
    var _args = Array.prototype.slice.call(arguments);

    // 在内部聲明一個函數,利用閉包的特性儲存_args并收集所有的參數值
    var _adder = function() {
        _args.push(...arguments);
        return _adder;
    };

    // 利用toString隐式轉換的特性,當最後執行時隐式轉換,并計算最終的值傳回
    _adder.toString = function () {
        return _args.reduce(function (a, b) {
            return a + b;
        });
    }
    return _adder;
}

add(1)(2)(3)                // 6
add(1, 2, 3)(4)             // 10
add(1)(2)(3)(4)(5)          // 15
add(2, 6)(1)                // 9

           

詳情介紹

繼續閱讀