前端基礎問題整理-JavaScript相關

請解釋事件代理(event delegation)

事件代理也稱爲事件委託,利用了事件冒泡。例如:javascript

<ul class="item-list">
    <li class="item">item1</li>
    <li class="item">item2</li>
    <li class="item">item3</li>
</ul>

當頁面li增多時單獨給每一個li元素添加事件處理程序既繁瑣又容易出錯,利用事件冒泡,在ul去監聽事件,li產生事件往上冒泡時去捕獲,利用e.target來判斷是否爲咱們的目標元素,是的話就能夠作相應操做了。html

請解釋JavaScriptthis是如何工做的。

  • 做爲獨立函數的調用java

function func(){
    console.log(this);
}


func();
//Window

全局做用域中聲明一個函數,並調用它,此時函數中的this指向全局對象。json

  • 做爲對象方法調用跨域

function say(){
    console.log(this);
}

var obj = {
    name: "f2er",
    say: say
};

obj.say();
//Object {name: "f2er"}

當函數做爲一個對象的方法調用時,函數中的this綁定到了這個對象。數組

  • 使用call或apply來調用函數瀏覽器

function func(){
    console.log(this);
}

var obj = {
    name:"f2er"
};

func.call(obj);
//Object {name: "f2er"}

func.apply(obj);
//Object {name: "f2er"}

當使用call()apply()函數進行函數調用時,傳入參數對象的將被設置爲函數體內this的值,這兩個函數都是設置調用函數體內的this值的,且第一個參數都爲this,區別是第二個參數apply()是一個參數arguments(類數組對象),而call(),傳遞給他的是一系列參數。安全

  • new來調用函數服務器

function F2er(name){
    this.name = name;   
    console.log(this);
}

var f2er = new F2er('f2er');
// F2er {name: "f2er"}

當使用new來調用一個函數時,會建立一個新的對象,而後綁定到Dog()調用中的this閉包

請解釋原型繼承(prototypal inheritance)的原理。

先上一個例子:

function Super(){
    this.superValue = "super";
}

Super.prototype.getSuperValue = function (){
    return this.superValue;
}

function Sub(){
    this.subValue = "sub";
}

var superInstance = new Super();

Sub.prototype = superInstance;

Sub.prototype.getSubValue = function (){
    return this.subValue;
}

var instance = new Sub();
console.log(instance.getSuperValue());
// super

每一個函數Sub都有一個屬性prototypeprototype指向一個原型對象,原型對象中也有一個指向函數的屬性constructor,經過new一個函數Sub能夠產生實例instance,調用這個instance的某個屬性或方法時,instance會先查找自身是否有這個方法或者屬性,沒有的話就會去實例的構造函數Sub的原型prototype中查找,即Sub.prototype,若是給原型對象Sub.prototype賦予另外一個類型的實例superInstance,則是在superInstance中查找的,這個superInstance中也有屬性prototype指向某個原型對象,以此一級級往上最終到Object.prototype,這樣就造成了原型繼承。

利用此原理能夠本身實現一個inherits函數:

function inherits(subType, superType){
    var _prototype = Object.create(superType.prototype);
    _prototype.constructor = subType;
    subType.prototype = _prototype;
}

IIFE(當即調用的函數表達式)是什麼?有什麼做用?

(function fn(){..})(),函數被包含在一個括號內,變成爲一個表達式,隨後跟着一個(),就當即執行這個函數,

這種模式就是當即執行函數表達式(Immediately Invoked Function Expression),簡稱IIFE。

也有用(function fn(){..}())後面的括號在前面的括號內這種形式表示的,這兩種形式在功能上都是一致的。

IIFE的一些做用:

  • 建立做用域,內部保存一些大量臨時變量的代碼防止命名衝突。

  • 一些庫的外層用這種形式包起來防止做用域污染。

  • 運行一些只執行一次的代碼。

(function(){

    var module = require('module');

    module.setup();

    module.run();

})();
  • 用閉包保存狀態

如下點擊頁面標籤的時候,實際並非彈出每一個具體的i的,而是elems.length,由於每一個a監聽器中引用的i都是同一個做用域的。

var elems = document.getElementsByTagName('a');

for (var i = 0; i < elems.length; i++) {
    elems[i].addEventListener('click', function (e) {
        e.preventDefault();
        alert('I am link #' + i);
    }, 'false');
}

如下點擊頁面標籤的時候,每個i傳入一個IIFEIIFE造成單獨一個做用域保存了當時的i值,因此點擊a標籤,能夠彈出不一樣的i值。

var elems = document.getElementsByTagName('a');

for (var i = 0; i < elems.length; i++) {
    (function (lockedInIndex) {
        elems[i].addEventListener('click', function (e) {
            e.preventDefault();
            alert('I am link #' + lockedInIndex);
        }, 'false');
    })(i);
}

什麼是閉包(closure),有什麼做用?

當某個函數調用時會建立一個執行環境以及做用域鏈,而後根據arguments和其它命名參數初始化造成活動對象。在外部函數調用結束後,其執行環境與做用域鏈被銷燬,可是其活動對象保存在了閉包之中,最後在閉包函數調用結束後才銷燬。簡單的說,閉包就是可以讀取其餘函數內部變量的函數。在js中,閉包是指有權訪問另外一個函數做用域中的變量的函數。

閉包的做用

  • 匿名自執行函數

有的場景下函數只須要執行一次,例如init()之類的函數,其內部變量無需維護,咱們可使用閉包。 咱們建立了一個匿名的函數,並當即執行它,因爲外部沒法引用它內部的變量,所以在函數執行完後會馬上釋放資源,並且不污染全局對象

  • 封裝

模擬面向對象的代碼風格進行封裝,使私有屬性存在成爲可能。

缺點

  • 常駐內存,會增大內存使用量,易形成內存泄露

請指出JavaScript宿主對象和原生對象的區別?

  • 宿主對象是指DOMBOM

  • 原生對象是Object、Function、Array、String、Boolean、Number、Date、RegExp、Error、Math等對象。

請指出如下代碼的區別:function Person(){}、var person = Person()、var person = new Person()?

  • function Person(){}

聲明一個函數Person()

  • var person = Person()

將函數Person()的結果返回給變量person,若是沒有返回值則personundefined

  • var person = new Person()

new一個Person的實例對象。

.call.apply的區別是什麼?

.call.apply的共同點是都是用來改變函數體內this對象的值。

區別是第二個參數不同。apply()的第二個參數是一個類數組對象arguments,參數都是以數組的形式傳入,而call(),傳遞給他的是一系列參數。例如

Math.max.call(null, 1, 2, 3, 4);
//4

Math.max.apply(null, [1, 2, 3, 4]);
//4

請解釋Function.prototype.bind

Function.prototype.bind方法會建立一個新函數,當這個新函數被調用時,它的this值是傳遞給bind()的第一個參數, 它的參數是bind()的其餘參數和其本來的參數.

Function.prototype.bind的實現相似於:

Function.prototype.bind = function (scope) {
    var fn = this;
    return function () {
        return fn.apply(scope, arguments);
    };
}

Function.prototype.bind的做用

  • 建立綁定函數

  • 一些函數的參數經常也是函數,給當作參數的函數綁定this值確保參數函數執行時有正確的this指向。

Ajax的工做原理

Ajax是無需刷新頁面就能從服務器取得數據的一種方法。

原理

Ajax經過XmlHttpRequest對象來向服務器發異步請求,從服務器得到數據,而後用javascript來操做DOM更新頁面。

過程

  1. 建立XMLHttpRequest對象。

  2. 設置響應HTTP請求的回調函數。

  3. 建立一個HTTP請求,指定相應的請求方法、url等。

  4. 發送HTTP請求。

  5. 獲取服務器端返回的數據。

  6. 使用JavaScript操做DOM更新頁面。

缺點

  • 對搜索引擎不友好

  • 要實現Ajax下的先後退功能成本較大

  • 跨域問題限制

JSONP的工做原理

JSONP(JSON with Padding)是一種非官方跨域數據交互協議,它容許在服務器端集成<script>標籤返回至客戶端,經過javascript回調的形式實現跨域訪問。

由於同源策略的緣由,咱們不能使用XMLHttpRequest與外部服務器進行通訊,可是<script>能夠訪問外部資源,因此經過JSON<script>相結合的辦法,能夠繞過同源策略從外部服務器直接取得可執行的JavaScript函數。

原理

客戶端定義一個函數,好比jsonpCallback,而後建立<script>srcurl + ?jsonp=jsonpCallback這樣的形式,以後服務器會生成一個和傳遞過來jsonpCallback同樣名字的參數,並把須要傳遞的數據當作參數傳入,好比jsonpCallback(json),而後返回給客戶端,此時客戶端就執行了這個服務器端返回的jsonpCallback(json)回調。

通俗的說,就是客戶端定義一個函數而後請求,服務器端返回的javascript內容就是調用這個函數,須要的數據都當作參數傳入這個函數了。

  • 優勢 - 兼容性好,簡單易用,支持瀏覽器與服務器雙向通訊

  • 缺點 - 只支持GET請求;存在腳本注入以及跨站請求僞造等安全問題

補充一點,JSONP不使用XMLHttpRequest對象加載資源,不屬於真正意義上的AJAX

變量聲明提高(hoisting)

變量的聲明前置就是把變量的聲明提高到當前做用域的最前面。

函數的聲明前置就是把整個函數提高到當前做用域的最前面(位於前置的變量聲明後面)。

//變量的聲明前置

console.log(num);//undefined

var num = 1;



等價於



//變量的聲明前置

var num;

console.log(num);//undefined

num = 1;
//函數的聲明前置

var num = 1;

console.log(doubleNum(num));//2

function doubleNum(num){

    return num*2;

}



等價於



//函數的聲明前置

var num;

function doubleNum(num){

    return num*2;

}

num = 1;

console.log(doubleNum(num));//2

事件冒泡機制(event bubbling)

事件冒泡(event bubbling),事件最開始時由觸發的那個元素身上發生,而後沿着DOM樹向上傳播,直到document對象。若是想阻止事件起泡,可使用e.stopPropagation()

JavaScript的同源策略

同源策略限制了一個源(origin)中加載文本或腳本與來自其它源(origin)中資源的交互方式。同源指的是協議、域名、端口相同,同源策略是一種安全協議。

目的

同源策略保證了用戶的信息安全,瀏覽器打開多個站點時,互相之間不能利用JavaScript獲取對方站點的敏感信息。

一些跨域技術

  • JSONP

  • CORS

  • 修改document.domain來進行跨域

  • 使用window.name來進行跨域

  • 使用window.postMessage來進行跨域

什麼是"use strict"?使用它的好處和壞處分別是什麼?

在全部語句以前放一個特定語句"use strict",就會爲整個script標籤開啓嚴格模式。

優勢

  • 消除Javascript語法的一些不嚴謹之處,減小一些怪異行爲;

  • 消除代碼運行的一些不安全之處,保證代碼運行的安全;

  • 提升編譯器效率,增長運行速度;

  • 爲將來新版本的Javascript作好鋪墊。

缺點

  • 嚴格模式改變了語義。依賴這些改變可能會致使沒有實現嚴格模式的瀏覽器中出現問題或者錯誤。

相關文章
相關標籤/搜索