1. 程式人生 > 其它 >前端面試-基礎知識5

前端面試-基礎知識5

JavaScript

1. JavaScript的組成

JavaScript 由以下三部分組成:
ECMAScript(核心):JavaScript 語言基礎
DOM(文件物件模型):規定了訪問HTML和XML的介面
BOM(瀏覽器物件模型):提供了瀏覽器視窗之間進行互動的物件和方法

2. JS的基本資料型別和引用資料型別

基本資料型別:undefined、null、boolean、number、string、symbol
引用資料型別:object、array、function

3. 檢測瀏覽器版本版本有哪些方式?

根據 navigator.userAgent // UA.toLowerCase().indexOf('chrome')
根據 window 物件的成員 // 'ActiveXObject' in window

4. 介紹JS有哪些內建物件?

資料封裝類物件:Object、Array、Boolean、Number、String
其他物件:Function、Arguments、Math、Date、RegExp、Error
ES6新增物件:Symbol、Map、Set、Promises、Proxy、Reflect

5. 說幾條寫JavaScript的基本規範?

程式碼縮排,建議使用“四個空格”縮排
程式碼段使用花括號{}包裹
語句結束使用分號;
變數和函式在使用前進行宣告
以大寫字母開頭命名建構函式,全大寫命名常量
規範定義JSON物件,補全雙引號
用{}和[]宣告物件和陣列
6. 如何編寫高效能的JavaScript?
遵循嚴格模式:"use strict";
將js指令碼放在頁面底部,加快渲染頁面
將js指令碼將指令碼成組打包,減少請求
使用非阻塞方式下載js指令碼
儘量使用區域性變數來儲存全域性變數
儘量減少使用閉包
使用 window 物件屬性方法時,省略 window
儘量減少物件成員巢狀
快取 DOM 節點的訪問
通過避免使用 eval() 和 Function() 構造器
給 setTimeout() 和 setInterval() 傳遞函式而不是字串作為引數
儘量使用直接量建立物件和陣列
最小化重繪(repaint)和迴流(reflow)
7. 描述瀏覽器的渲染過程,DOM樹和渲染樹的區別?
瀏覽器的渲染過程:

解析HTML構建 DOM(DOM樹),並行請求 css/image/js
CSS 檔案下載完成,開始構建 CSSOM(CSS樹)
CSSOM 構建結束後,和 DOM 一起生成 Render Tree(渲染樹)
佈局(Layout):計算出每個節點在螢幕中的位置
顯示(Painting):通過顯示卡把頁面畫到螢幕上
DOM樹 和 渲染樹 的區別:

DOM樹與HTML標籤一一對應,包括head和隱藏元素
渲染樹不包括head和隱藏元素,大段文字的每一個行都是獨立節點,每一個節點都有對應的css屬性
8. 重繪和迴流(重排)的區別和關係?
重繪:當渲染樹中的元素外觀(如:顏色)發生改變,不影響佈局時,產生重繪
迴流:當渲染樹中的元素的佈局(如:尺寸、位置、隱藏/狀態狀態)發生改變時,產生重繪迴流
注意:JS獲取Layout屬性值(如:offsetLeft、scrollTop、getComputedStyle等)也會引起迴流。因為瀏覽器需要通過迴流計算最新值
迴流必將引起重繪,而重繪不一定會引起迴流
9. 如何最小化重繪(repaint)和迴流(reflow)?
需要要對元素進行復雜的操作時,可以先隱藏(display:"none"),操作完成後再顯示
需要建立多個DOM節點時,使用DocumentFragment建立完後一次性的加入document
快取Layout屬性值,如:var left = elem.offsetLeft; 這樣,多次使用 left 只產生一次迴流
儘量避免用table佈局(table元素一旦觸發迴流就會導致table裡所有的其它元素迴流)
避免使用css表示式(expression),因為每次呼叫都會重新計算值(包括載入頁面)
儘量使用 css 屬性簡寫,如:用 border 代替 border-width, border-style, border-color
批量修改元素樣式:elem.className 和 elem.style.cssText 代替 elem.style.xxx
10. script 的位置是否會影響首屏顯示時間?
在解析 HTML 生成 DOM 過程中,js 檔案的下載是並行的,不需要 DOM 處理到 script 節點。因此,script的位置不影響首屏顯示的開始時間。
瀏覽器解析 HTML 是自上而下的線性過程,script作為 HTML 的一部分同樣遵循這個原則
因此,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間
11. 解釋JavaScript中的作用域與變數宣告提升?
JavaScript作用域:

在Java、C等語言中,作用域為for語句、if語句或{}內的一塊區域,稱為作用域;
而在 JavaScript 中,作用域為function(){}內的區域,稱為函式作用域。
JavaScript變數宣告提升:

在JavaScript中,函式宣告與變數宣告經常被JavaScript引擎隱式地提升到當前作用域的頂部。
宣告語句中的賦值部分並不會被提升,只有名稱被提升
函式宣告的優先順序高於變數,如果變數名跟函式名相同且未賦值,則函式宣告會覆蓋變數宣告
如果函式有多個同名引數,那麼最後一個引數(即使沒有定義)會覆蓋前面的同名引數
12. 介紹JavaScript的原型,原型鏈?有什麼特點?
原型:

JavaScript的所有物件中都包含了一個 [proto] 內部屬性,這個屬性所對應的就是該物件的原型
JavaScript的函式物件,除了原型 [proto] 之外,還預置了 prototype 屬性
當函式物件作為建構函式建立例項時,該 prototype 屬性值將被作為例項物件的原型 [proto]。
原型鏈:

當一個物件呼叫的屬性/方法自身不存在時,就會去自己 [proto] 關聯的前輩 prototype 物件上去找
如果沒找到,就會去該 prototype 原型 [proto] 關聯的前輩 prototype 去找。依次類推,直到找到屬性/方法或 undefined 為止。從而形成了所謂的“原型鏈”
原型特點:
JavaScript物件是通過引用來傳遞的,當修改原型時,與之相關的物件也會繼承這一改變
13. JavaScript有幾種型別的值?,你能畫一下他們的記憶體圖嗎
原始資料型別(Undefined,Null,Boolean,Number、String)-- 棧
引用資料型別(物件、陣列和函式)-- 堆
兩種型別的區別是:儲存位置不同:
原始資料型別是直接儲存在棧(stack)中的簡單資料段,佔據空間小、大小固定,屬於被頻繁使用資料;
引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定,如果儲存在棧中,將會影響程式執行的效能;
引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。
當直譯器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。
14. JavaScript如何實現一個類,怎麼例項化這個類?
建構函式法(this + prototype) -- 用 new 關鍵字 生成例項物件
缺點:用到了 this 和 prototype,編寫複雜,可讀性差
function Mobile(name, price){
this.name = name;
this.price = price;
}
Mobile.prototype.sell = function(){
alert(this.name + ",售價 $" + this.price);
}
var iPhone7 = new Mobile("iPhone7", 1000);
iPhone7.sell();
Object.create 法 -- 用 Object.create() 生成例項物件
缺點:不能實現私有屬性和私有方法,例項物件之間也不能共享資料
var Person = {
firstname: "Mark",
lastname: "Yun",
age: 25,
introduce: function(){
alert('I am ' + Person.firstname + ' ' + Person.lastname);
}
};

var person = Object.create(Person);
person.introduce();

// Object.create 要求 IE9+,低版本瀏覽器可以自行部署:
if (!Object.create) {
  Object.create = function (o) {
    function F() {}
    F.prototype = o;
    return new F();
  };
 }
極簡主義法(消除 this 和 prototype) -- 呼叫 createNew() 得到例項物件
優點:容易理解,結構清晰優雅,符合傳統的"面向物件程式設計"的構造
var Cat = {
age: 3, // 共享資料 -- 定義在類物件內,createNew() 外
createNew: function () {
var cat = {};
// var cat = Animal.createNew(); // 繼承 Animal 類
cat.name = "小咪";
var sound = "喵喵喵"; // 私有屬性--定義在 createNew() 內,輸出物件外
cat.makeSound = function () {
alert(sound); // 暴露私有屬性
};
cat.changeAge = function(num){
Cat.age = num; // 修改共享資料
};
return cat; // 輸出物件
}
};

var cat = Cat.createNew();
cat.makeSound();
ES6 語法糖 class -- 用 new 關鍵字 生成例項物件
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return '(' + this.x + ', ' + this.y + ')';
}
}

var point = new Point(2, 3);
15. Javascript如何實現繼承?
建構函式繫結:使用 call 或 apply 方法,將父物件的建構函式繫結在子物件上


- 例項繼承:將子物件的 prototype 指向父物件的一個例項     

```javascript
Cat.prototype = new Animal();
Cat.prototype.constructor = Cat;
拷貝繼承:如果把父物件的所有屬性和方法,拷貝進子物件
```javascript    function extend(Child, Parent) {    var p = Parent.prototype;    var c = Child.prototype;    for (var i in p) {     c[i] = p[i];    }    c.uber = p;   }

- 原型繼承:將子物件的 prototype 指向父物件的 prototype      

```javascript
    function extend(Child, Parent) {
        var F = function(){};
       F.prototype = Parent.prototype;
       Child.prototype = new F();
       Child.prototype.constructor = Child;
       Child.uber = Parent.prototype;
    }
ES6 語法糖 extends:class ColorPoint extends Point {}
    class ColorPoint extends Point {
       constructor(x, y, color) {
          super(x, y); // 呼叫父類的constructor(x, y)
          this.color = color;
       }
       toString() {
          return this.color + ' ' + super.toString(); // 呼叫父類的toString()
       }
    }
16. Javascript作用鏈域?
全域性函式無法檢視區域性函式的內部細節,但區域性函式可以檢視其上層的函式細節,直至全域性細節
如果當前作用域沒有找到屬性或方法,會向上層作用域查詢,直至全域性函式,這種形式就是作用域鏈 eval是做什麼的?
17. eval的功能是把對應的字串解析成JS程式碼並執行
應該避免使用eval,不安全,非常耗效能(先解析成js語句,再執行)
由JSON字串轉換為JSON物件的時候可以用 eval('('+ str +')');
18. 什麼是 Window 物件? 什麼是 Document 物件?
Window 物件表示當前瀏覽器的視窗,是JavaScript的頂級物件。
我們建立的所有物件、函式、變數都是 Window 物件的成員。
Window 物件的方法和屬性是在全域性範圍內有效的。
Document 物件是 HTML 文件的根節點與所有其他節點(元素節點,文字節點,屬性節點, 註釋節點)
Document 物件使我們可以通過指令碼對 HTML 頁面中的所有元素進行訪問
Document 物件是 Window 物件的一部分,可通過 window.document 屬性對其進行訪問
19. 介紹 DOM 的發展
DOM:文件物件模型(Document Object Model),定義了訪問HTML和XML文件的標準,與程式語言及平臺無關
DOM0:提供了查詢和操作Web文件的內容API。未形成標準,實現混亂。如:document.forms['login']
DOM1:W3C提出標準化的DOM,簡化了對文件中任意部分的訪問和操作。如:JavaScript中的Document物件
DOM2:原來DOM基礎上擴充了滑鼠事件等細分模組,增加了對CSS的支援。如:getComputedStyle(elem, pseudo)
DOM3:增加了XPath模組和載入與儲存(Load and Save)模組。如:XPathEvaluator
20. 介紹DOM0,DOM2,DOM3事件處理方式區別
DOM0級事件處理方式:
btn.onclick = func;
btn.onclick = null;
DOM2級事件處理方式:
btn.addEventListener('click', func, false);
btn.removeEventListener('click', func, false);
btn.attachEvent("onclick", func);
btn.detachEvent("onclick", func);
DOM3級事件處理方式:
eventUtil.addListener(input, "textInput", func);
eventUtil 是自定義物件,textInput 是DOM3級事件
21. 事件的三個階段
捕獲、目標、冒泡
22. 介紹事件“捕獲”和“冒泡”執行順序和事件的執行次數?
按照W3C標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段
事件執行次數(DOM2-addEventListener):元素上繫結事件的個數
注意1:前提是事件被確實觸發
注意2:事件繫結幾次就算幾個事件,即使型別和功能完全一樣也不會“覆蓋”
事件執行順序:判斷的關鍵是否目標元素
非目標元素:根據W3C的標準執行:捕獲->目標元素->冒泡(不依據事件繫結順序)
目標元素:依據事件繫結順序:先繫結的事件先執行(不依據捕獲冒泡標準)
最終順序:父元素捕獲->目標元素事件1->目標元素事件2->子元素捕獲->子元素冒泡->父元素冒泡
注意:子元素事件執行前提 事件確實“落”到子元素佈局區域上,而不是簡單的具有巢狀關係
23. 在一個DOM上同時繫結兩個點選事件:一個用捕獲,一個用冒泡。事件會執行幾次,先執行冒泡還是捕獲?
該DOM上的事件如果被觸發,會執行兩次(執行次數等於繫結次數)
如果該DOM是目標元素,則按事件繫結順序執行,不區分冒泡/捕獲
如果該DOM是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡
24. 事件的代理/委託
事件委託是指將事件繫結目標元素的到父元素上,利用冒泡機制觸發該事件
優點:
可以減少事件註冊,節省大量記憶體佔用
可以將事件應用於動態新增的子元素上
缺點: 使用不當會造成事件在不應該觸發時觸發
示例:
ulEl.addEventListener('click', function(e){
    var target = event.target || event.srcElement;
    if(!!target && target.nodeName.toUpperCase() === "LI"){
        console.log(target.innerHTML);
    }
}, false);
25. IE與火狐的事件機制有什麼區別? 如何阻止冒泡?
IE只事件冒泡,不支援事件捕獲;火狐同時支援件冒泡和事件捕獲
IE的事件處理和W3C的事件處理有哪些區別?

繫結事件

W3C: targetEl.addEventListener('click', handler, false);
IE: targetEl.attachEvent('onclick', handler);
刪除事件

W3C: targetEl.removeEventListener('click', handler, false);
IE: targetEl.detachEvent(event, handler);
事件物件

W3C: var e = arguments.callee.caller.arguments[0]
IE: window.event
事件目標

W3C: e.target
IE: window.event.srcElement
阻止事件預設行為

W3C: e.preventDefault()
IE: window.event.returnValue = false
阻止事件傳播

W3C: e.stopPropagation()
IE: window.event.cancelBubble = true
26. W3C事件的 target 與 currentTarget 的區別?
target 只會出現在事件流的目標階段
currentTarget 可能出現在事件流的任何階段
當事件流處在目標階段時,二者的指向相同
當事件流處於捕獲或冒泡階段時:currentTarget 指向當前事件活動的物件(一般為父級)
27. 如何派發事件(dispatchEvent)?(如何進行事件廣播?)
W3C: 使用 dispatchEvent 方法
IE: 使用 fireEvent 方法
var fireEvent = function(element, event){
    if (document.createEventObject){
        var mockEvent = document.createEventObject();
        return element.fireEvent('on' + event, mockEvent)
    }else{
        var mockEvent = document.createEvent('HTMLEvents');
        mockEvent.initEvent(event, true, true);
        return !element.dispatchEvent(mockEvent);
    }
}
28. 什麼是函式節流?介紹一下應用場景和原理?
函式節流(throttle)是指阻止一個函式在很短時間間隔內連續呼叫。 只有當上一次函式執行後達到規定的時間間隔,才能進行下一次呼叫。 但要保證一個累計最小呼叫間隔(否則拖拽類的節流都將無連續效果)

函式節流用於 onresize, onscroll 等短時間內會多次觸發的事件

函式節流的原理:使用定時器做時間節流。 當觸發一個事件時,先用 setTimout 讓這個事件延遲一小段時間再執行。 如果在這個時間間隔內又觸發了事件,就 clearTimeout 原來的定時器, 再 setTimeout 一個新的定時器重複以上流程。

函式節流簡單實現:

function throttle(method, context) {
     clearTimeout(methor.tId);
     method.tId = setTimeout(function(){
         method.call(context);
     }, 100); // 兩次呼叫至少間隔 100ms
}
// 呼叫
window.onresize = function(){
    throttle(myFunc, window);
}
29. 區分什麼是“客戶區座標”、“頁面座標”、“螢幕座標”?
客戶區座標:滑鼠指標在可視區中的水平座標(clientX)和垂直座標(clientY)
頁面座標:滑鼠指標在頁面佈局中的水平座標(pageX)和垂直座標(pageY)
螢幕座標:裝置物理螢幕的水平座標(screenX)和垂直座標(screenY)
30. 如何獲得一個DOM元素的絕對位置?
elem.offsetLeft:返回元素相對於其定位父級左側的距離
elem.offsetTop:返回元素相對於其定位父級頂部的距離
elem.getBoundingClientRect():返回一個DOMRect物件,包含一組描述邊框的只讀屬性,單位畫素
31. 分析 ['1', '2', '3'].map(parseInt) 答案是多少?
答案:[1, NaN, NaN]
parseInt(string, radix) 第2個引數 radix 表示進位制。省略 radix 或 radix = 0,則數字將以十進位制解析
map 每次為 parseInt 傳3個引數(elem, index, array),其中 index 為陣列索引
因此,map 遍歷 ["1", "2", "3"],相應 parseInt 接收引數如下
parseInt('1', 0);  // 1
parseInt('2', 1);  // NaN
parseInt('3', 2);  // NaN
所以,parseInt 引數 radix 不合法,導致返回值為 NaN
32. new 操作符具體幹了什麼?
建立例項物件,this 變數引用該物件,同時還繼承了建構函式的原型
屬性和方法被加入到 this 引用的物件中
新建立的物件由 this 所引用,並且最後隱式的返回 this
33. 用原生JavaScript的實現過什麼功能嗎?
封裝選擇器、呼叫第三方API、設定和獲取樣式
34. 解釋一下這段程式碼的意思嗎?
  [].forEach.call($$("*"), function(el){
      el.style.outline = "1px solid #" + (~~(Math.random()*(1<<24))).toString(16);
  })
解釋:獲取頁面所有的元素,遍歷這些元素,為它們新增1畫素隨機顏色的輪廓(outline)
$$(sel) // $$函式被許多現代瀏覽器命令列支援,等價於 document.querySelectorAll(sel)
[].forEach.call(NodeLists) // 使用 call 函式將陣列遍歷函式 forEach 應到節點元素列表
el.style.outline = "1px solid #333" // 樣式 outline 位於盒模型之外,不影響元素佈局位置
(1<<24) // parseInt("ffffff", 16) 16777215 2^24 - 1 // 1<<24 2^24 16777216
Math.random()*(1<<24) // 表示一個位於 0 到 16777216 之間的隨機浮點數
~~Math.random()*(1<<24) // ~~ 作用相當於 parseInt 取整
(~~(Math.random()*(1<<24))).toString(16) // 轉換為一個十六進位制-
35. JavaScript實現非同步程式設計的方法?
回撥函式
事件監聽
釋出/訂閱
Promises物件
Async函式[ES7]
36. web開發中會話跟蹤的方法有哪些
cookie
session
url重寫
隱藏input
ip地址
37. 介紹js的基本資料型別
Undefined、Null、Boolean、Number、String
38. 介紹js有哪些內建物件?
Object 是 JavaScript 中所有物件的父物件
資料封裝類物件:Object、Array、Boolean、Number 和 String
其他物件:Function、Arguments、Math、Date、RegExp、Error
39. 說幾條寫JavaScript的基本規範?
不要在同一行宣告多個變數
請使用 =/!來比較true/false或者數值
使用物件字面量替代new Array這種形式
不要使用全域性函式
Switch語句必須帶有default分支
函式不應該有時候有返回值,有時候沒有返回值
If語句必須使用大括號
for-in迴圈中的變數 應該使用var關鍵字明確限定作用域,從而避免作用域汙
40. JavaScript原型,原型鏈 ? 有什麼特點?
每個物件都會在其內部初始化一個屬性,就是prototype(原型),當我們訪問一個物件的屬性時
如果這個物件內部不存在這個屬性,那麼他就會去prototype裡找這個屬性,這個prototype又會有自己的prototype,於是就這樣一直找下去,也就是我們平時所說的原型鏈的概念
關係:instance.constructor.prototype = instance.__proto__
特點:

JavaScript物件是通過引用來傳遞的,我們建立的每個新物件實體中並沒有一份屬於自己的原型副本。當我們修改原型時,與之相關的物件也會繼承這一改變。
當我們需要一個屬性的時,Javascript引擎會先看當前物件中是否有這個屬性, 如果沒有的

就會查詢他的Prototype物件是否有這個屬性,如此遞推下去,一直檢索到 Object 內建物件
41. JavaScript有幾種型別的值?,你能畫一下他們的記憶體圖嗎?
棧:原始資料型別(Undefined,Null,Boolean,Number、String)
堆:引用資料型別(物件、陣列和函式)

兩種型別的區別是:儲存位置不同;

原始資料型別直接儲存在棧(stack)中的簡單資料段,佔據空間小、大小固定,屬於被頻繁使用資料,所以放入棧中儲存;
引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定,如果儲存在棧中,將會影響程式執行的效能;引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。當直譯器尋找引用值時,會首先檢索其
在棧中的地址,取得地址後從堆中獲得實體


42. Javascript如何實現繼承?
構造繼承
原型繼承
例項繼承
拷貝繼承

原型prototype機制或apply和call方法去實現較簡單,建議使用建構函式與原型混合方式

 function Parent(){
        this.name = 'wang';
    }

    function Child(){
        this.age = 28;
    }
    Child.prototype = new Parent();//繼承了Parent,通過原型

    var demo = new Child();
    alert(demo.age);
    alert(demo.name);//得到被繼承的屬性
  }
43. javascript建立物件的幾種方式?
javascript建立物件簡單的說,無非就是使用內建物件或各種自定義物件,當然還可以用JSON;但寫法有很多種,也能混合使用

物件字面量的方式
person={firstname:"Mark",lastname:"Yun",age:25,eyecolor:"black"};
用function來模擬無參的建構函式
 function Person(){}
    var person=new Person();//定義一個function,如果使用new"例項化",該function可以看作是一個Class
        person.name="Mark";
        person.age="25";
        person.work=function(){
        alert(person.name+" hello...");
    }
person.work();
用function來模擬參建構函式來實現(用this關鍵字定義構造的上下文屬性)
function Pet(name,age,hobby){
       this.name=name;//this作用域:當前物件
       this.age=age;
       this.hobby=hobby;
       this.eat=function(){
          alert("我叫"+this.name+",我喜歡"+this.hobby+",是個程式設計師");
       }
    }
    var maidou =new Pet("麥兜",25,"coding");//例項化、建立物件
    maidou.eat();//呼叫eat方法
用工廠方式來建立(內建物件)
var wcDog =new Object();
     wcDog.name="旺財";
     wcDog.age=3;
     wcDog.work=function(){
       alert("我是"+wcDog.name+",汪汪汪......");
     }
     wcDog.work();
用原型方式來建立
function Dog(){

     }
     Dog.prototype.name="旺財";
     Dog.prototype.eat=function(){
     alert(this.name+"是個吃貨");
     }
     var wangcai =new Dog();
     wangcai.eat();
用混合方式來建立
 function Car(name,price){
      this.name=name;
      this.price=price;
    }
     Car.prototype.sell=function(){
       alert("我是"+this.name+",我現在賣"+this.price+"萬元");
      }
    var camry =new Car("凱美瑞",27);
    camry.sell();
44. Javascript作用鏈域?
全域性函式無法檢視區域性函式的內部細節,但區域性函式可以檢視其上層的函式細節,直至全域性細節
當需要從區域性函式查詢某一屬性或方法時,如果當前作用域沒有找到,就會上溯到上層作用域查詢
直至全域性函式,這種組織形式就是作用域鏈
45. 談談This物件的理解
this總是指向函式的直接呼叫者(而非間接呼叫者)
如果有new關鍵字,this指向new出來的那個物件
在事件中,this指向觸發這個事件的物件,特殊的是,IE中的attachEvent中的this總是指向全域性物件Window
46. eval是做什麼的?
它的功能是把對應的字串解析成JS程式碼並執行
應該避免使用eval,不安全,非常耗效能(2次,一次解析成js語句,一次執行)
由JSON字串轉換為JSON物件的時候可以用eval,var obj =eval('('+ str +')')
47. null,undefined 的區別?
undefined 表示不存在這個值。
undefined :是一個表示"無"的原始值或者說表示"缺少值",就是此處應該有一個值,但是還沒有定義。當嘗試讀取時會返回 undefined
例如變數被聲明瞭,但沒有賦值時,就等於undefined

null 表示一個物件被定義了,值為“空值”

null : 是一個物件(空物件, 沒有任何屬性和方法)
例如作為函式的引數,表示該函式的引數不是物件;

在驗證null時,一定要使用 = ,因為 無法分別 null 和 undefined

48. 寫一個通用的事件偵聽器函式
 // event(事件)工具集,來源:github.com/markyun
    markyun.Event = {
        // 頁面載入完成後
        readyEvent : function(fn) {
            if (fn==null) {
                fn=document;
            }
            var oldonload = window.onload;
            if (typeof window.onload != 'function') {
                window.onload = fn;
            } else {
                window.onload = function() {
                    oldonload();
                    fn();
                };
            }
        },
        // 視能力分別使用dom0||dom2||IE方式 來繫結事件
        // 引數: 操作的元素,事件名稱 ,事件處理程式
        addEvent : function(element, type, handler) {
            if (element.addEventListener) {
                //事件型別、需要執行的函式、是否捕捉
                element.addEventListener(type, handler, false);
            } else if (element.attachEvent) {
                element.attachEvent('on' + type, function() {
                    handler.call(element);
                });
            } else {
                element['on' + type] = handler;
            }
        },
        // 移除事件
        removeEvent : function(element, type, handler) {
            if (element.removeEventListener) {
                element.removeEventListener(type, handler, false);
            } else if (element.datachEvent) {
                element.detachEvent('on' + type, handler);
            } else {
                element['on' + type] = null;
            }
        },
        // 阻止事件 (主要是事件冒泡,因為IE不支援事件捕獲)
        stopPropagation : function(ev) {
            if (ev.stopPropagation) {
                ev.stopPropagation();
            } else {
                ev.cancelBubble = true;
            }
        },
        // 取消事件的預設行為
        preventDefault : function(event) {
            if (event.preventDefault) {
                event.preventDefault();
            } else {
                event.returnValue = false;
            }
        },
        // 獲取事件目標
        getTarget : function(event) {
            return event.target || event.srcElement;
        },
        // 獲取event物件的引用,取到事件的所有資訊,確保隨時能使用event;
        getEvent : function(e) {
            var ev = e || window.event;
            if (!ev) {
                var c = this.getEvent.caller;
                while (c) {
                    ev = c.arguments[0];
                    if (ev && Event == ev.constructor) {
                        break;
                    }
                    c = c.caller;
                }
            }
            return ev;
        }
    };
["1", "2", "3"].map(parseInt) 答案是多少?

[1, NaN, NaN] 因為 parseInt 需要兩個引數 (val, radix),其中 radix 表示解析時用的基數。
map 傳了 3 個 (element, index, array),對應的 radix 不合法導致解析失敗。
48. 事件是?IE與火狐的事件機制有什麼區別? 如何阻止冒泡?
我們在網頁中的某個操作(有的操作對應多個事件)。例如:當我們點選一個按鈕就會產生一個事件。是可以被 JavaScript 偵測到的行為
事件處理機制:IE是事件冒泡、Firefox同時支援兩種事件模型,也就是:捕獲型事件和冒泡型事件
ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)
49. 什麼是閉包(closure),為什麼要用它?
閉包是指有權訪問另一個函式作用域中變數的函式,建立閉包的最常見的方式就是在一個函式內建立另一個函式,通過另一個函式訪問這個函式的區域性變數,利用閉包可以突破作用鏈域

閉包的特性:

函式內再巢狀函式
內部函式可以引用外層的引數和變數
引數和變數不會被垃圾回收機制回收
50. javascript 程式碼中的"use strict";是什麼意思 ? 使用它區別是什麼?
use strict是一種ECMAscript 5 新增的(嚴格)執行模式,這種模式使得 Javascript 在更嚴格的條件下執行,使JS編碼更加規範化的模式,消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為
51. 如何判斷一個物件是否屬於某個類?
// 使用instanceof (待完善)
   if(a instanceof Person){
       alert('yes');
   }
52. new操作符具體幹了什麼呢?
建立一個空物件,並且 this 變數引用該物件,同時還繼承了該函式的原型
屬性和方法被加入到 this 引用的物件中
新建立的物件由 this 所引用,並且最後隱式的返回 this
var obj  = {};
obj.__proto__ = Base.prototype;
Base.call(obj);
53. js延遲載入的方式有哪些?
defer和async、動態建立DOM方式(用得最多)、按需非同步載入js
54. Ajax 是什麼? 如何建立一個Ajax?
ajax的全稱:Asynchronous Javascript And XML

非同步傳輸+js+xml
所謂非同步,在這裡簡單地解釋就是:向伺服器傳送請求的時候,我們不必等待結果,而是可以同時做其他的事情,等到有了結果它自己會根據設定進行後續操作,與此同時,頁面是不會發生整頁重新整理的,提高了使用者體驗

建立XMLHttpRequest物件,也就是建立一個非同步呼叫物件

建一個新的HTTP請求,並指定該HTTP請求的方法、URL及驗證資訊
設定響應HTTP請求狀態變化的函式
傳送HTTP請求
獲取非同步呼叫返回的資料
用JavaScript和DOM實現區域性重新整理
55. 同步和非同步的區別?
同步:瀏覽器訪問伺服器請求,使用者看得到頁面重新整理,重新發請求,等請求完,頁面重新整理,新內容出現,使用者看到新內容,進行下一步操作
非同步:瀏覽器訪問伺服器請求,使用者正常操作,瀏覽器後端進行請求。等請求完,頁面不重新整理,新內容也會出現,使用者看到新內容
56. 非同步載入JS的方式有哪些?
defer,只支援IE
async:
建立script,插入到DOM中,載入完畢後callBack
57. documen.write和 innerHTML的區別
document.write只能重繪整個頁面
innerHTML可以重繪頁面的一部分
58. DOM操作——怎樣新增、移除、移動、複製、建立和查詢節點?
(1)建立新節點
createDocumentFragment() //建立一個DOM片段
createElement() //建立一個具體的元素
createTextNode() //建立一個文字節點
(2)新增、移除、替換、插入
appendChild()
removeChild()
replaceChild()
insertBefore() //在已有的子節點前插入一個新的子節點
(3)查詢
getElementsByTagName() //通過標籤名稱
getElementsByName() // 通過元素的Name屬性的值(IE容錯能力較強,會得到一個數組,其中包括id等於name值的)
getElementById() //通過元素Id,唯一性
59. 那些操作會造成記憶體洩漏?
記憶體洩漏指任何物件在您不再擁有或需要它之後仍然存在
垃圾回收器定期掃描物件,並計算引用了每個物件的其他物件的數量。如果一個物件的引用數量為 0(沒有其他物件引用過該物件),或對該物件的惟一引用是迴圈的,那麼該物件的記憶體即可回收
setTimeout 的第一個引數使用字串而非函式的話,會引發記憶體洩漏
閉包、控制檯日誌、迴圈(在兩個物件彼此引用且彼此保留時,就會產生一個迴圈)
60. 漸進增強和優雅降級
漸進增強 :針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高階瀏覽器進行效果、互動等改進和追加功能達到更好的使用者體驗。

優雅降級 :一開始就構建完整的功能,然後再針對低版本瀏覽器進行相容

61. Javascript垃圾回收方法
標記清除(mark and sweep)
這是JavaScript最常見的垃圾回收方式,當變數進入執行環境的時候,比如函式中宣告一個變數,垃圾回收器將其標記為“進入環境”,當變數離開環境的時候(函式執行結束)將其標記為“離開環境”
垃圾回收器會在執行的時候給儲存在記憶體中的所有變數加上標記,然後去掉環境中的變數以及被環境中變數所引用的變數(閉包),在這些完成之後仍存在標記的就是要刪除的變量了
引用計數(reference counting)
在低版本IE中經常會出現記憶體洩露,很多時候就是因為其採用引用計數方式進行垃圾回收。引用計數的策略是跟蹤記錄每個值被使用的次數,當聲明瞭一個 變數並將一個引用型別賦值給該變數的時候這個值的引用次數就加1,如果該變數的值變成了另外一個,則這個值得引用次數減1,當這個值的引用次數變為0的時 候,說明沒有變數在使用,這個值沒法被訪問了,因此可以將其佔用的空間回收,這樣垃圾回收器會在執行的時候清理掉引用次數為0的值佔用的空間

62. js繼承方式及其優缺點
原型鏈繼承的缺點

一是字面量重寫原型會中斷關係,使用引用型別的原型,並且子型別還無法給超型別傳遞引數。
借用建構函式(類式繼承)

借用建構函式雖然解決了剛才兩種問題,但沒有原型,則複用無從談起。所以我們需要原型鏈+借用建構函式的模式,這種模式稱為組合繼承
組合式繼承

組合式繼承是比較常用的一種繼承方法,其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而通過借用建構函式來實現對例項屬性的繼承。這樣,既通過在原型上定義方法實現了函式複用,又保證每個例項都有它自己的屬性。
63. defer和async
defer並行載入js檔案,會按照頁面上script標籤的順序執行async並行載入js檔案,下載完成立即執行,不會按照頁面上script標籤的順序執行
用過哪些設計模式?

工廠模式:
主要好處就是可以消除物件間的耦合,通過使用工程方法而不是new關鍵字。將所有例項化的程式碼集中在一個位置防止程式碼重複
工廠模式解決了重複例項化的問題 ,但還有一個問題,那就是識別問題,因為根本無法 搞清楚他們到底是哪個物件的例項 - ``` function createObject(name,age,profession){//集中例項化的函式var obj = new Object(); obj.name = name; obj.age = age; obj.profession = profession; obj.move = function () {
return this.name + ' at ' + this.age + ' engaged in ' + this.profession;
}; return obj; } var test1 = createObject('trigkit4',22,'programmer');//第一個例項var test2 = createObject('mike',25,'engineer');//第二個例項

- 建構函式模式
  - 使用建構函式的方法 ,即解決了重複例項化的問題 ,又解決了物件識別的問題,該模式與工廠模式的不同之處在於

- 建構函式方法沒有顯示的建立物件 (new Object());

- 直接將屬性和方法賦值給 this 物件;

- 沒有 renturn 語句

### 64. 說說你對閉包的理解

- 使用閉包主要是為了設計私有的方法和變數。閉包的優點是可以避免全域性變數的汙染,缺點是閉包會常駐記憶體,會增大記憶體使用量,使用不當很容易造成記憶體洩露。在js中,函式即閉包,只有函式才會產生作用域的概念

- 閉包有三個特性:
  - 1.函式巢狀函式

  - 2.函式內部可以引用外部的引數和變數

  - 3.引數和變數不會被垃圾回收機制回收



### 65. 請解釋一下 JavaScript 的同源策略

- 概念:同源策略是客戶端指令碼(尤其是Javascript)的重要的安全度量標準。它最早出自Netscape Navigator2.0,其目的是防止某個文件或指令碼從多個不同源裝載。這裡的同源策略指的是:協議,域名,埠相同,同源策略是一種安全協議
- 指一段指令碼只能讀取來自同一來源的視窗和文件的屬性

### 66. 為什麼要有同源限制?

- 我們舉例說明:比如一個黑客程式,他利用Iframe把真正的銀行登入頁面嵌到他的頁面上,當你使用真實的使用者名稱,密碼登入時,他的頁面就可以通過Javascript讀取到你的表單中input中的內容,這樣使用者名稱,密碼就輕鬆到手了。
- 缺點
  - 現在網站的JS都會進行壓縮,一些檔案用了嚴格模式,而另一些沒有。這時這些本來是嚴格模式的檔案,被 merge後,這個串就到了檔案的中間,不僅沒有指示嚴格模式,反而在壓縮後浪費了位元組

### 67. 實現一個函式clone,可以對JavaScript中的5種主要的資料型別(包括Number、String、Object、Array、Boolean)進行值複製
Object.prototype.clone = function(){

        var o = this.constructor === Array ? [] : {};

        for(var e in this){

                o[e] = typeof this[e] === "object" ? this[e].clone() : this[e];

        }

        return o;
}

說說嚴格模式的限制

  - 嚴格模式主要有以下限制:

  - 變數必須聲明後再使用

  - 函式的引數不能有同名屬性,否則報錯

  - 不能使用with語句

  - 不能對只讀屬性賦值,否則報錯

  - 不能使用字首0表示八進位制數,否則報錯

  - 不能刪除不可刪除的屬性,否則報錯

  - 不能刪除變數delete prop,會報錯,只能刪除屬性delete global[prop]

  - eval不會在它的外層作用域引入變數

  - eval和arguments不能被重新賦值

  - arguments不會自動反映函式引數的變化

  - 不能使用arguments.callee

  - 不能使用arguments.caller

  - 禁止this指向全域性物件

  - 不能使用fn.caller和fn.arguments獲取函式呼叫的堆疊

  - 增加了保留字(比如protected、static和interface)

### 68. 如何刪除一個cookie?

- 將時間設為當前時間往前一點
var date = new Date();

date.setDate(date.getDate() - 1);//真正的刪除

### 69. setDate()方法用於設定一個月的某一天

- expires的設定
document.cookie = 'user='+ encodeURIComponent('name') + ';expires = ' + new Date(0)



### 70. 編寫一個方法 求一個字串的位元組長度

- 假設:一個英文字元佔用一個位元組,一箇中文字元佔用兩個位元組
function GetBytes(str){

    var len = str.length;

    var bytes = len;

    for(var i=0; i<len; i++){

        if (str.charCodeAt(i) > 255) bytes++;

    }

    return bytes;

}
alert(GetBytes("你好,as"));


### 71. 請解釋什麼是事件代理

- 事件代理(Event Delegation),又稱之為事件委託。是 JavaScript 中常用繫結事件的常用技巧。顧名思義,“事件代理”即是把原本需要繫結的事件委託給父元素,讓父元素擔當事件監聽的職務。事件代理的原理是DOM元素的事件冒泡。使用事件代理的好處是可以提高效能

attribute和property的區別是什麼?

- attribute是dom元素在文件中作為html標籤擁有的屬性;
- property就是dom元素在js中作為物件擁有的屬性。

- 對於html的標準屬性來說,attribute和property是同步的,是會自動更新的
- 但是對於自定義的屬性來說,他們是不同步的

### 72. 頁面編碼和被請求的資源編碼如果不一致如何處理?

 * 後端響應頭設定 charset
 * 前端頁面`<meta>`設定 charset


把`<script>`放在`</body>`之前和之後有什麼區別?瀏覽器會如何解析它們?

 * 按照HTML標準,在`</body>`結束後出現`<script>`或任何元素的開始標籤,都是解析錯誤
 * 雖然不符合HTML標準,但瀏覽器會自動容錯,使實際效果與寫在`</body>`之前沒有區別
 * 瀏覽器的容錯機制會忽略<script>之前的`</body>`,視作`<script>`仍在 body 體內。省略`</body>`和`</html>`閉合標籤符合HTML標準,伺服器可以利用這一標準儘可能少輸出內容

### 73. 延遲載入JS的方式有哪些?

* 設定`<script>`屬性 defer="defer" (指令碼將在頁面完成解析時執行)
* 動態建立 script DOM:document.createElement('script');
* XmlHttpRequest 指令碼注入
* 延遲載入工具 LazyLoad

### 74. 非同步載入JS的方式有哪些?

* 設定`<script>`屬性 async="async" (一旦指令碼可用,則會非同步執行)
* 動態建立 script DOM:document.createElement('script');
* XmlHttpRequest 指令碼注入
* 非同步載入庫 LABjs
* 模組載入器 Sea.js

### 75. JavaScript 中,呼叫函式有哪幾種方式?

* 方法呼叫模式          Foo.foo(arg1, arg2);
* 函式呼叫模式          foo(arg1, arg2);
* 構造器呼叫模式        (new Foo())(arg1, arg2);
* call/applay呼叫模式   Foo.foo.call(that, arg1, arg2);
* bind呼叫模式          Foo.foo.bind(that)(arg1, arg2)();


### 76. 簡單實現 Function.bind 函式?

```javascript
  if (!Function.prototype.bind) {
    Function.prototype.bind = function(that) {
      var func = this, args = arguments;
      return function() {
        return func.apply(that, Array.prototype.slice.call(args, 1));
      }
    }
  }
  // 只支援 bind 階段的預設引數:
  func.bind(that, arg1, arg2)();

  // 不支援以下呼叫階段傳入的引數:
  func.bind(that)(arg1, arg2);
77. 列舉一下JavaScript陣列和物件有哪些原生方法?
陣列:

arr.concat(arr1, arr2, arrn);
arr.join(",");
arr.sort(func);
arr.pop();
arr.push(e1, e2, en);
arr.shift();
unshift(e1, e2, en);
arr.reverse();
arr.slice(start, end);
arr.splice(index, count, e1, e2, en);
arr.indexOf(el);
arr.includes(el); // ES6
物件:

object.hasOwnProperty(prop);
object.propertyIsEnumerable(prop);
object.valueOf();
object.toString();
object.toLocaleString();
Class.prototype.isPropertyOf(object);
79. Array.splice() 與 Array.splice() 的區別?
slice -- “讀取”陣列指定的元素,不會對原陣列進行修改

語法:arr.slice(start, end)
start 指定選取開始位置(含)
end 指定選取結束位置(不含)

splice

“操作”陣列指定的元素,會修改原陣列,返回被刪除的元素
語法:arr.splice(index, count, [insert Elements])
index 是操作的起始位置
count = 0 插入元素,count > 0 刪除元素
[insert Elements] 向陣列新插入的元素
80. JavaScript 物件生命週期的理解?
當建立一個物件時,JavaScript 會自動為該物件分配適當的記憶體
垃圾回收器定期掃描物件,並計算引用了該物件的其他物件的數量
如果被引用數量為 0,或惟一引用是迴圈的,那麼該物件的記憶體即可回收
81. 哪些操作會造成記憶體洩漏?
JavaScript 記憶體洩露指物件在不需要使用它時仍然存在,導致佔用的記憶體不能使用或回收
未使用 var 宣告的全域性變數
閉包函式(Closures)
迴圈引用(兩個物件相互引用)
控制檯日誌(console.log)
移除存在繫結事件的DOM元素(IE)