1. 程式人生 > >前端面試指南之js篇

前端面試指南之js篇

JavaScript


JavaScript的組成

  • JavaScript 由以下三部分組成:

    • ECMAScript(核心):JavaScript 語言基礎

    • DOM(文件物件模型):規定了訪問HTML和XML的介面

    • BOM(瀏覽器物件模型):提供了瀏覽器視窗之間進行互動的物件和方法

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

  • 基本資料型別:undefined、null、boolean、number、string、symbol

  • 引用資料型別:object、array、function

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

  • 根據 navigator.userAgent // UA.toLowerCase().indexOf('chrome')

  • 根據 window 物件的成員 // 'ActiveXObject' in window

介紹JS有哪些內建物件?

  • 資料封裝類物件:Object、Array、Boolean、Number、String

  • 其他物件:Function、Arguments、Math、Date、RegExp、Error

  • ES6新增物件:Symbol、Map、Set、Promises、Proxy、Reflect

說幾條寫JavaScript的基本規範?

  • 程式碼縮排,建議使用“四個空格”縮排

  • 程式碼段使用花括號{}包裹

  • 語句結束使用分號;

  • 變數和函式在使用前進行宣告

  • 以大寫字母開頭命名建構函式,全大寫命名常量

  • 規範定義JSON物件,補全雙引號

  • 用{}和[]宣告物件和陣列

如何編寫高效能的JavaScript?

  • 遵循嚴格模式:"use strict";

  • 將js指令碼放在頁面底部,加快渲染頁面

  • 將js指令碼將指令碼成組打包,減少請求

  • 使用非阻塞方式下載js指令碼

  • 儘量使用區域性變數來儲存全域性變數

  • 儘量減少使用閉包

  • 使用 window 物件屬性方法時,省略 window

  • 儘量減少物件成員巢狀

  • 快取 DOM 節點的訪問

  • 通過避免使用 eval() 和 Function() 構造器

  • 給 setTimeout() 和 setInterval() 傳遞函式而不是字串作為引數

  • 儘量使用直接量建立物件和陣列

  • 最小化重繪(repaint)和迴流(reflow)

描述瀏覽器的渲染過程,DOM樹和渲染樹的區別?

  • 瀏覽器的渲染過程:

    • 解析HTML構建 DOM(DOM樹),並行請求 css/image/js

    • CSS 檔案下載完成,開始構建 CSSOM(CSS樹)

    • CSSOM 構建結束後,和 DOM 一起生成 Render Tree(渲染樹)

    • 佈局(Layout):計算出每個節點在螢幕中的位置

    • 顯示(Painting):通過顯示卡把頁面畫到螢幕上

  • DOM樹 和 渲染樹 的區別:

    • DOM樹與HTML標籤一一對應,包括head和隱藏元素

    • 渲染樹不包括head和隱藏元素,大段文字的每一個行都是獨立節點,每一個節點都有對應的css屬性

重繪和迴流(重排)的區別和關係?

  • 重繪:當渲染樹中的元素外觀(如:顏色)發生改變,不影響佈局時,產生重繪

  • 迴流:當渲染樹中的元素的佈局(如:尺寸、位置、隱藏/狀態狀態)發生改變時,產生重繪迴流

  • 注意:JS獲取Layout屬性值(如:offsetLeft、scrollTop、getComputedStyle等)也會引起迴流。因為瀏覽器需要通過迴流計算最新值

  • 迴流必將引起重繪,而重繪不一定會引起迴流

如何最小化重繪(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

script 的位置是否會影響首屏顯示時間?

  • 在解析 HTML 生成 DOM 過程中,js 檔案的下載是並行的,不需要 DOM 處理到 script 節點。因此,script的位置不影響首屏顯示的開始時間。

  • 瀏覽器解析 HTML 是自上而下的線性過程,script作為 HTML 的一部分同樣遵循這個原則

  • 因此,script 會延遲 DomContentLoad,只顯示其上部分首屏內容,從而影響首屏顯示的完成時間

解釋JavaScript中的作用域與變數宣告提升?

  • JavaScript作用域:

    • 在Java、C等語言中,作用域為for語句、if語句或{}內的一塊區域,稱為作用域;

    • 而在 JavaScript 中,作用域為function(){}內的區域,稱為函式作用域。

  • JavaScript變數宣告提升:

    • 在JavaScript中,函式宣告與變數宣告經常被JavaScript引擎隱式地提升到當前作用域的頂部。

    • 宣告語句中的賦值部分並不會被提升,只有名稱被提升

    • 函式宣告的優先順序高於變數,如果變數名跟函式名相同且未賦值,則函式宣告會覆蓋變數宣告

    • 如果函式有多個同名引數,那麼最後一個引數(即使沒有定義)會覆蓋前面的同名引數

介紹JavaScript的原型,原型鏈?有什麼特點?

  • 原型:

    • JavaScript的所有物件中都包含了一個 [proto] 內部屬性,這個屬性所對應的就是該物件的原型

    • JavaScript的函式物件,除了原型 [proto] 之外,還預置了 prototype 屬性

    • 當函式物件作為建構函式建立例項時,該 prototype 屬性值將被作為例項物件的原型 [proto]。

  • 原型鏈:

    • 當一個物件呼叫的屬性/方法自身不存在時,就會去自己 [proto] 關聯的前輩 prototype 物件上去找

    • 如果沒找到,就會去該 prototype 原型 [proto] 關聯的前輩 prototype 去找。依次類推,直到找到屬性/方法或 undefined 為止。從而形成了所謂的“原型鏈”

  • 原型特點:

    • JavaScript物件是通過引用來傳遞的,當修改原型時,與之相關的物件也會繼承這一改變

JavaScript有幾種型別的值?,你能畫一下他們的記憶體圖嗎

  • 原始資料型別(Undefined,Null,Boolean,Number、String)-- 棧

  • 引用資料型別(物件、陣列和函式)-- 堆

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

  • 原始資料型別是直接儲存在棧(stack)中的簡單資料段,佔據空間小、大小固定,屬於被頻繁使用資料;

  • 引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定,如果儲存在棧中,將會影響程式執行的效能;

  • 引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。

  • 當直譯器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中獲得實體。

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);

Javascript如何實現繼承?

  • 建構函式繫結:使用 call 或 apply 方法,將父物件的建構函式繫結在子物件上

 

function Cat(name,color){  Animal.apply(this, arguments);  this.name = name;  this.color = color; }

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

 

Cat.prototype = new Animal(); Cat.prototype.constructor = Cat;

  • 拷貝繼承:如果把父物件的所有屬性和方法,拷貝進子物件

 

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

 

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()       }    }

Javascript作用鏈域?

  • 全域性函式無法檢視區域性函式的內部細節,但區域性函式可以檢視其上層的函式細節,直至全域性細節

  • 如果當前作用域沒有找到屬性或方法,會向上層作用域查詢,直至全域性函式,這種形式就是作用域鏈

談談this物件的理解

  • this 總是指向函式的直接呼叫者

  • 如果有 new 關鍵字,this 指向 new 出來的例項物件

  • 在事件中,this指向觸發這個事件的物件

  • IE下 attachEvent 中的this總是指向全域性物件Window

eval是做什麼的?

eval的功能是把對應的字串解析成JS程式碼並執行

  • 應該避免使用eval,不安全,非常耗效能(先解析成js語句,再執行)

  • 由JSON字串轉換為JSON物件的時候可以用 eval('('+ str +')');

什麼是 Window 物件? 什麼是 Document 物件?

  • Window 物件表示當前瀏覽器的視窗,是JavaScript的頂級物件。

  • 我們建立的所有物件、函式、變數都是 Window 物件的成員。

  • Window 物件的方法和屬性是在全域性範圍內有效的。

  • Document 物件是 HTML 文件的根節點與所有其他節點(元素節點,文字節點,屬性節點, 註釋節點)

  • Document 物件使我們可以通過指令碼對 HTML 頁面中的所有元素進行訪問

  • Document 物件是 Window 物件的一部分,可通過 window.document 屬性對其進行訪問

介紹 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

介紹DOM0,DOM2,DOM3事件處理方式區別

btn.onclick = func;

btn.onclick = null;

btn.addEventListener('click', func, false);

btn.removeEventListener('click', func, false);

btn.attachEvent("onclick", func);

btn.detachEvent("onclick", func);

eventUtil.addListener(input, "textInput", func);

eventUtil 是自定義物件,textInput 是DOM3級事件

  • DOM0級事件處理方式:

  • DOM2級事件處理方式:

  • DOM3級事件處理方式:

事件的三個階段

  • 捕獲、目標、冒泡

介紹事件“捕獲”和“冒泡”執行順序和事件的執行次數?

注意1:前提是事件被確實觸發

注意2:事件繫結幾次就算幾個事件,即使型別和功能完全一樣也不會“覆蓋”

非目標元素:根據W3C的標準執行:捕獲->目標元素->冒泡(不依據事件繫結順序)

目標元素:依據事件繫結順序:先繫結的事件先執行(不依據捕獲冒泡標準)

最終順序:父元素捕獲->目標元素事件1->目標元素事件2->子元素捕獲->子元素冒泡->父元素冒泡

注意:子元素事件執行前提 事件確實“落”到子元素佈局區域上,而不是簡單的具有巢狀關係

  • 按照W3C標準的事件:首是進入捕獲階段,直到達到目標元素,再進入冒泡階段

  • 事件執行次數(DOM2-addEventListener):元素上繫結事件的個數

  • 事件執行順序:判斷的關鍵是否目標元素

在一個DOM上同時繫結兩個點選事件:一個用捕獲,一個用冒泡。事件會執行幾次,先執行冒泡還是捕獲?

  • 該DOM上的事件如果被觸發,會執行兩次(執行次數等於繫結次數)

  • 如果該DOM是目標元素,則按事件繫結順序執行,不區分冒泡/捕獲

  • 如果該DOM是處於事件流中的非目標元素,則先執行捕獲,後執行冒泡

事件的代理/委託

  • 事件委託是指將事件繫結目標元素的到父元素上,利用冒泡機制觸發該事件

    • 可以減少事件註冊,節省大量記憶體佔用

    • 可以將事件應用於動態新增的子元素上

    • 優點:

    • 缺點: 使用不當會造成事件在不應該觸發時觸發

    • 示例:

 

ulEl.addEventListener('click', function(e){    var target = event.target || event.srcElement;    if(!!target && target.nodeName.toUpperCase() === "LI"){        console.log(target.innerHTML);    } }, false);

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

W3C事件的 target 與 currentTarget 的區別?

  • target 只會出現在事件流的目標階段

  • currentTarget 可能出現在事件流的任何階段

  • 當事件流處在目標階段時,二者的指向相同

  • 當事件流處於捕獲或冒泡階段時:currentTarget 指向當前事件活動的物件(一般為父級)

如何派發事件(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);    } }

什麼是函式節流?介紹一下應用場景和原理?

  • 函式節流(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); }

區分什麼是“客戶區座標”、“頁面座標”、“螢幕座標”?

  • 客戶區座標:滑鼠指標在可視區中的水平座標(clientX)和垂直座標(clientY)

  • 頁面座標:滑鼠指標在頁面佈局中的水平座標(pageX)和垂直座標(pageY)

  • 螢幕座標:裝置物理螢幕的水平座標(screenX)和垂直座標(screenY)

如何獲得一個DOM元素的絕對位置?

  • elem.offsetLeft:返回元素相對於其定位父級左側的距離

  • elem.offsetTop:返回元素相對於其定位父級頂部的距離

  • elem.getBoundingClientRect():返回一個DOMRect物件,包含一組描述邊框的只讀屬性,單位畫素

分析 ['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

new 操作符具體幹了什麼?

  • 建立例項物件,this 變數引用該物件,同時還繼承了建構函式的原型

  • 屬性和方法被加入到 this 引用的物件中

  • 新建立的物件由 this 所引用,並且最後隱式的返回 this

用原生JavaScript的實現過什麼功能嗎?

  • 封裝選擇器、呼叫第三方API、設定和獲取樣式

解釋一下這段程式碼的意思嗎?

 

[].forEach.call($$("*"), function(el){      el.style.outline = "1px solid #" + (~~(Math.random()*(1<<24))).toString(16);  })

  • 解釋:獲取頁面所有的元素,遍歷這些元素,為它們新增1畫素隨機顏色的輪廓(outline)

  •  

    1. $$(sel) // $$函式被許多現代瀏覽器命令列支援,等價於 document.querySelectorAll(sel)

  •  

    1. [].forEach.call(NodeLists) // 使用 call 函式將陣列遍歷函式 forEach 應到節點元素列表

  •  

    1. el.style.outline = "1px solid #333" // 樣式 outline 位於盒模型之外,不影響元素佈局位置

  •  

    1. (1<<24) // parseInt("ffffff", 16) == 16777215 == 2^24 - 1 // 1<<24 == 2^24 == 16777216

  •  

    1. Math.random()*(1<<24) // 表示一個位於 0 到 16777216 之間的隨機浮點數

  •  

    1. ~~Math.random()*(1<<24) // ~~ 作用相當於 parseInt 取整

  •  

    1. (~~(Math.random()*(1<<24))).toString(16) // 轉換為一個十六進位制-

JavaScript實現非同步程式設計的方法?

  • 回撥函式

  • 事件監聽

  • 釋出/訂閱

  • Promises物件

  • Async函式[ES7]

web開發中會話跟蹤的方法有哪些

  • cookie

  • session

  • url重寫

  • 隱藏input

  • ip地址

介紹js的基本資料型別

  • Undefined、Null、Boolean、Number、String

介紹js有哪些內建物件?

  • Object 是 JavaScript 中所有物件的父物件

  • 資料封裝類物件:Object、Array、Boolean、Number 和 String

  • 其他物件:Function、Arguments、Math、Date、RegExp、Error

說幾條寫JavaScript的基本規範?

  • 不要在同一行宣告多個變數

  • 請使用 ===/!==來比較true/false或者數值

  • 使用物件字面量替代new Array這種形式

  • 不要使用全域性函式

  • Switch語句必須帶有default分支

  • 函式不應該有時候有返回值,有時候沒有返回值

  • If語句必須使用大括號

  • for-in迴圈中的變數 應該使用var關鍵字明確限定作用域,從而避免作用域汙

JavaScript原型,原型鏈 ? 有什麼特點?

  • 每個物件都會在其內部初始化一個屬性,就是prototype(原型),當我們訪問一個物件的屬性時

  • 如果這個物件內部不存在這個屬性,那麼他就會去prototype裡找這個屬性,這個prototype又會有自己的prototype,於是就這樣一直找下去,也就是我們平時所說的原型鏈的概念

  • 關係:instance.constructor.prototype = instance.__proto__

  • 特點:

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

  • 當我們需要一個屬性的時,Javascript引擎會先看當前物件中是否有這個屬性, 如果沒有的

  • 就會查詢他的Prototype物件是否有這個屬性,如此遞推下去,一直檢索到 Object 內建物件

JavaScript有幾種型別的值?,你能畫一下他們的記憶體圖嗎?

  • 棧:原始資料型別(Undefined,Null,Boolean,Number、String)

  • 堆:引用資料型別(物件、陣列和函式)

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

  • 原始資料型別直接儲存在棧(stack)中的簡單資料段,佔據空間小、大小固定,屬於被頻繁使用資料,所以放入棧中儲存;

  • 引用資料型別儲存在堆(heap)中的物件,佔據空間大、大小不固定,如果儲存在棧中,將會影響程式執行的效能;引用資料型別在棧中儲存了指標,該指標指向堆中該實體的起始地址。當直譯器尋找引用值時,會首先檢索其

  • 在棧中的地址,取得地址後從堆中獲得實體

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);//得到被繼承的屬性  }

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();

Javascript作用鏈域?

  • 全域性函式無法檢視區域性函式的內部細節,但區域性函式可以檢視其上層的函式細節,直至全域性細節

  • 當需要從區域性函式查詢某一屬性或方法時,如果當前作用域沒有找到,就會上溯到上層作用域查詢

  • 直至全域性函式,這種組織形式就是作用域鏈

談談This物件的理解

  • this總是指向函式的直接呼叫者(而非間接呼叫者)

  • 如果有new關鍵字,this指向new出來的那個物件

  • 在事件中,this指向觸發這個事件的物件,特殊的是,IE中的attachEvent中的this總是指向全域性物件Window

eval是做什麼的?

  • 它的功能是把對應的字串解析成JS程式碼並執行

  • 應該避免使用eval,不安全,非常耗效能(2次,一次解析成js語句,一次執行)

  • 由JSON字串轉換為JSON物件的時候可以用eval,var obj =eval('('+ str +')')

null,undefined 的區別?

  • undefined 表示不存在這個值。

  • undefined :是一個表示"無"的原始值或者說表示"缺少值",就是此處應該有一個值,但是還沒有定義。當嘗試讀取時會返回 undefined

  • 例如變數被聲明瞭,但沒有賦值時,就等於undefined

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

  • null : 是一個物件(空物件, 沒有任何屬性和方法)

  • 例如作為函式的引數,表示該函式的引數不是物件;

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

寫一個通用的事件偵聽器函式

 

// 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 不合法導致解析失敗。

事件是?IE與火狐的事件機制有什麼區別? 如何阻止冒泡?

  • 我們在網頁中的某個操作(有的操作對應多個事件)。例如:當我們點選一個按鈕就會產生一個事件。是可以被 JavaScript 偵測到的行為

  • 事件處理機制:IE是事件冒泡、Firefox同時支援兩種事件模型,也就是:捕獲型事件和冒泡型事件

  • ev.stopPropagation();(舊ie的方法 ev.cancelBubble = true;)

什麼是閉包(closure),為什麼要用它?

  • 閉包是指有權訪問另一個函式作用域中變數的函式,建立閉包的最常見的方式就是在一個函式內建立另一個函式,通過另一個函式訪問這個函式的區域性變數,利用閉包可以突破作用鏈域

  • 閉包的特性:

    • 函式內再巢狀函式

    • 內部函式可以引用外層的引數和變數

    • 引數和變數不會被垃圾回收機制回收

javascript 程式碼中的"use strict";是什麼意思 ? 使用它區別是什麼?

  • use strict是一種ECMAscript 5 新增的(嚴格)執行模式,這種模式使得 Javascript 在更嚴格的條件下執行,使JS編碼更加規範化的模式,消除Javascript語法的一些不合理、不嚴謹之處,減少一些怪異行為

如何判斷一個物件是否屬於某個類?

 

// 使用instanceof (待完善)   if(a instanceof Person){       alert('yes');   }

new操作符具體幹了什麼呢?

  • 建立一個空物件,並且 this 變數引用該物件,同時還繼承了該函式的原型

  • 屬性和方法被加入到 this 引用的物件中

  • 新建立的物件由 this 所引用,並且最後隱式的返回 this

 

var obj  = {}; obj.__proto__ = Base.prototype; Base.call(obj);

js延遲載入的方式有哪些?

  • defer和async、動態建立DOM方式(用得最多)、按需非同步載入js

Ajax 是什麼? 如何建立一個Ajax?

ajax的全稱:Asynchronous Javascript And XML

  • 非同步傳輸+js+xml

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

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

  • 建一個新的HTTP請求,並指定該HTTP請求的方法、URL及驗證資訊

  • 設定響應HTTP請求狀態變化的函式

  • 傳送HTTP請求

  • 獲取非同步呼叫返回的資料

  • 用JavaScript和DOM實現區域性重新整理

同步和非同步的區別?

  • 同步:瀏覽器訪問伺服器請求,使用者看得到頁面重新整理,重新發請求,等請求完,頁面重新整理,新內容出現,使用者看到新內容,進行下一步操作

  • 非同步:瀏覽器訪問伺服器請求,使用者正常操作,瀏覽器後端進行請求。等請求完,頁面不重新整理,新內容也會出現,使用者看到新內容

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

  • defer,只支援IE

  • async:

  • 建立script,插入到DOM中,載入完畢後callBack

documen.write和 innerHTML的區別

  • document.write只能重繪整個頁面

  • innerHTML可以重繪頁面的一部分

DOM操作——怎樣新增、移除、移動、複製、建立和查詢節點?

  • (1)建立新節點

    • createDocumentFragment() //建立一個DOM片段

    • createElement() //建立一個具體的元素

    • createTextNode() //建立一個文字節點

  • (2)新增、移除、替換、插入

    • appendChild()

    • removeChild()

    • replaceChild()

    • insertBefore() //在已有的子節點前插入一個新的子節點

  • (3)查詢

    • getElementsByTagName() //通過標籤名稱

    • getElementsByName() // 通過元素的Name屬性的值(IE容錯能力較強,會得到一個數組,其中包括id等於name值的)

    • getElementById() //通過元素Id,唯一性

那些操作會造成記憶體洩漏?

  • 記憶體洩漏指任何物件在您不再擁有或需要它之後仍然存在

  • 垃圾回收器定期掃描物件,並計算引用了每個物件的其他物件的數量。如果一個物件的引用數量為 0(沒有其他物件引用過該物件),或對該物件的惟一引用是迴圈的,那麼該物件的記憶體即可回收

  • setTimeout 的第一個引數使用字串而非函式的話,會引發記憶體洩漏

  • 閉包、控制檯日誌、迴圈(在兩個物件彼此引用且彼此保留時,就會產生一個迴圈)

漸進增強和優雅降級

  • 漸進增強 :針對低版本瀏覽器進行構建頁面,保證最基本的功能,然後再針對高階瀏覽器進行效果、互動等改進和追加功能達到更好的使用者體驗。

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

Javascript垃圾回收方法

  • 標記清除(mark and sweep)

  • 這是JavaScript最常見的垃圾回收方式,當變數進入執行環境的時候,比如函式中宣告一個變數,垃圾回收器將其標記為“進入環境”,當變數離開環境的時候(函式執行結束)將其標記為“離開環境”

  • 垃圾回收器會在執行的時候給儲存在記憶體中的所有變數加上標記,然後去掉環境中的變數以及被環境中變數所引用的變數(閉包),在這些完成之後仍存在標記的就是要刪除的變量了

引用計數(reference counting)

在低版本IE中經常會出現記憶體洩露,很多時候就是因為其採用引用計數方式進行垃圾回收。引用計數的策略是跟蹤記錄每個值被使用的次數,當聲明瞭一個 變數並將一個引用型別賦值給該變數的時候這個值的引用次數就加1,如果該變數的值變成了另外一個,則這個值得引用次數減1,當這個值的引用次數變為0的時 候,說明沒有變數在使用,這個值沒法被訪問了,因此可以將其佔用的空間回收,這樣垃圾回收器會在執行的時候清理掉引用次數為0的值佔用的空間

js繼承方式及其優缺點

  • 原型鏈繼承的缺點

    • 一是字面量重寫原型會中斷關係,使用引用型別的原型,並且子型別還無法給超型別傳遞引數。

  • 借用建構函式(類式繼承)

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

  • 組合式繼承

    • 組合式繼承是比較常用的一種繼承方法,其背後的思路是使用原型鏈實現對原型屬性和方法的繼承,而通過借用建構函式來實現對例項屬性的繼承。這樣,既通過在原型上定義方法實現了函式複用,又保證每個例項都有它自己的屬性。

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 語句

說說你對閉包的理解

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

  • 閉包有三個特性:

    • 1.函式巢狀函式

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

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

請解釋一下 JavaScript 的同源策略

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

  • 指一段指令碼只能讀取來自同一來源的視窗和文件的屬性

為什麼要有同源限制?

  • 我們舉例說明:比如一個黑客程式,他利用Iframe把真正的銀行登入頁面嵌到他的頁面上,當你使用真實的使用者名稱,密碼登入時,他的頁面就可以通過Javascript讀取到你的表單中input中的內容,這樣使用者名稱,密碼就輕鬆到手了。

  • 缺點

    • 現在網站的JS都會進行壓縮,一些檔案用了嚴格模式,而另一些沒有。這時這些本來是嚴格模式的檔案,被 merge後,這個串就到了檔案的中間,不僅沒有指示嚴格模式,反而在壓縮後浪費了位元組

實現一個函式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)

如何刪除一個cookie

  • 將時間設為當前時間往前一點

 

var date = new Date(); date.setDate(date.getDate() - 1);//真正的刪除

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

  • expires的設定

 

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

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

  • 假設:一個英文字元佔用一個位元組,一箇中文字元佔用兩個位元組

 

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"));

請解釋什麼是事件代理

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

attribute和property的區別是什麼?

  • attribute是dom元素在文件中作為html標籤擁有的屬性;

  • property就是dom元素在js中作為物件擁有的屬性。

  • 對於html的標準屬性來說,attribute和property是同步的,是會自動更新的

  • 但是對於自定義的屬性來說,他們是不同步的

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

  • 後端響應頭設定 charset

  • 前端頁面<meta>設定 charset

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

  • 按照HTML標準,在</body>結束後出現<script>或任何元素的開始標籤,都是解析錯誤

  • 雖然不符合HTML標準,但瀏覽器會自動容錯,使實際效果與寫在</body>之前沒有區別

  • 瀏覽器的容錯機制會忽略