js面試題(上)

https://segmentfault.com/a/11...javascript

原型 / 構造函數 / 實例

  • 對原型的理解
咱們知道在es6以前,js沒有類和繼承的概念,js是經過原型來實現繼承的。在js中一個構造函數默認自帶有一個prototype屬性, 這個的屬性值是一個對象,同時這個prototype對象自帶有一個constructor屬性,這個屬性指向這個構造函數,同時每個實例 都有一個__proto__屬性指向這個prototype對象,咱們能夠將這個叫作隱式原型,咱們在使用一個實例的方法的時候,會先檢查 這個實例中是否有這個方法,沒有則會繼續向上查找這個prototype對象是否有這個方法,剛剛咱們說到prototype是一個對象, 那麼也便是說這個是一個對象的實例,那麼這個對象一樣也會有一個__proto__屬性指向對象的prototype對象。

原型鏈

JS 原型與原型鏈前端

執行上下文(EC)

變量對象

  • javascript有哪些方法定義對象

對象字面量: var obj = {};
構造函數: var obj = new Object();
Object.create(): var obj = Object.create(Object.prototype);java

做用域

做用域鏈

做用域鏈的原理和原型鏈很相似,若是這個變量在本身的做用域中沒有,那麼它會尋找父級的,直到最頂層。
注意:JS沒有塊級做用域,若要造成塊級做用域,可經過(function(){})();當即執行的形式實現。git

閉包

閉包指的是一個函數能夠訪問另外一個函數做用域中變量。常見的構造方法,是在一個函數內部定義另一個函數。內部函數能夠引用外層的變量;外層變量不會被垃圾回收機制回收。
注意,閉包的原理是做用域鏈,因此閉包訪問的上級做用域中的變量是個對象,其值爲其運算結束後的最後一個值。
優勢:避免全局變量污染。缺點:容易形成內存泄漏。
例子:程序員

function makeFunc() {
    var name = "Mozilla";
    function displayName() {
        console.log(name); 
    }
    return displayName;
}
var myFunc = makeFunc();
myFunc();   //輸出Mozilla

myFunc 變成一個 閉包。閉包是一種特殊的對象。它由兩部分構成:函數,以及建立該函數的環境。環境由閉包建立時在做用域中的任何局部變量組成。在咱們的例子中,myFunc 是一個閉包,由 displayName 函數和閉包建立時存在的 "Mozilla" 字符串造成。es6

script引入方式

對象的拷貝

這道題考察瞭如下知識點:
使用 typeof 判斷值得類型;
使用 toString 區分數組和對象;
遞歸函數的使用;
  • 實現一個函數 clone(),能夠對 JavaScript 中的5種主要的數據類型(包括 Number、String、Object、Array、Boolean)進行值複製。
function clone(obj) {
    //判斷是對象,就進行循環複製
    if (typeof obj === 'object' && typeof obj !== 'null') {
        // 區分是數組仍是對象,建立空的數組或對象
        var o = Object.prototype.toString.call(obj).slice(8, -1) === "Array" ? [] : {};
        for (var k in obj) {
            // 若是屬性對應的值爲對象,則遞歸複製
            if(typeof obj[k] === 'object' && typeof obj[k] !== 'null'){
                o[k] = clone(obj[k])
            }else{
                o[k] = obj[k];
            }
        }
    }else{ //不爲對象,直接把值返回
        return obj;
    }
    return o;
}

new運算符的執行過程

1) 建立一個空對象,而且 this 變量引用該對象,同時還繼承了該函數的原型。
2) 屬性和方法被加入到 this 引用的對象中。
3) 新建立的對象由 this 所引用,而且最後隱式的返回 this 。github

使用new操做符實例化一個對象的具體步驟
1.構造一個新的對象
2.將構造函數的做用域賦給新對象(也就是說this指向了新的對象)
3.執行構造函數中的代碼
4.返回新對象面試

instanceof原理

代碼的複用

繼承

其餘問題

js數據類型

其餘問題
  • typeof 返回哪些數據類型
typeof 返回七種值:
「number」、「string」、「boolean」、「object」、"symbol"、「function」和「undefined」。
typeof undefined、null、NaN分別返回undefined,object,number
  • JavaScript有幾種類型的值?你能畫一下他們的內存圖嗎?
基本數據類型存儲在棧中,引用數據類型(對象)存儲在堆中,指針放在棧中。
兩種類型的區別是:存儲位置不一樣;原始數據類型直接存儲在棧中的簡單數據段,佔據空間小、大小固定,屬於被頻繁使用數據,因此放入棧中存儲;引用數據類型存儲在堆中的對象,佔據空間大、大小不固定,若是存儲在棧中,將會影響程序運行的性能
引用數據類型在棧中存儲了指針,該指針指向堆中該實體的起始地址。當解釋器尋找引用值時,會首先檢索其在棧中的地址,取得地址後從堆中得到實體。
  • 棧和堆的區別
棧(stack):由編譯器自動分配釋放,存放函數的參數值,局部變量等;
堆(heap):通常由程序員分配釋放,若程序員不釋放,程序結束時可能由操做系統釋放。

類型轉換

  • 對象到數字的轉換步驟
  1. 若是對象有valueOf()方法而且返回元素值,javascript將返回值轉換爲數字做爲結果
  2. 不然,若是對象有toString()而且返回原始值,javascript將返回結果轉換爲數字做爲結果
  3. 不然,throws a TypeError
  • 對象到字符串的轉換步驟

1.若是對象有toString()方法,javascript調用它。若是返回一個原始值(primitive value如:string number boolean),將這個值轉換爲字符串做爲結果
2.若是對象沒有toString()方法或者返回值不是原始值,javascript尋找對象的valueOf()方法,若是存在就調用它,返回結果是原始值則轉爲字符串做爲結果
3.不然,javascript不能從toString()或者valueOf()得到一個原始值,此時throws a TypeError編程

類型判斷

  • javascript作類型判斷的方法有哪些?

typeof、instanceof 、 Object.prototype.toString()(待續)json

  • 實現一個類型判斷函數,須要鑑別出基本類型、function、null、NaN、數組、對象?

只須要鑑別這些類型那麼使用typeof便可,要鑑別null先判斷雙等判斷是否爲null,以後使用typeof判斷,若是是obejct的話,再用Array.isArray判斷 是否爲數組,若是是數字再使用isNaN判斷是否爲NaN,(須要注意的是NaN並非JavaScript數據類型,而是一種特殊值)以下:

function type(ele) {
  if(ele===null) {
    return null;
  } else if(typeof ele === 'object') {
    if(Array.isArray(ele)) {
      return 'array';
    } else {
      return typeof ele;
    }
  } else if(typeof ele === 'number') {
    if(isNaN(ele)) {
      return NaN;
    } else {
      return typeof ele;
    }
  } else{
    return typeof ele;
  }
}

模塊化

  • 對js模塊化的理解

在ES6出現以前,js沒有標準的模塊化概念,這也就形成了js多人寫做開發容易形成全局污染的狀況,之前咱們可能會採用當即執行 函數、對象等方式來儘可能減小變量這種狀況,後面社區爲了解決這個問題陸續提出了AMD規範和CMD規範,這裏不一樣於Node.js的 CommonJS的緣由在於服務端全部的模塊都是存在於硬盤中的,加載和讀取幾乎是不須要時間的,而瀏覽器端由於加載速度取決於網速, 所以須要採用異步加載,AMD規範中使用define來定義一個模塊,使用require方法來加載一個模塊,如今ES6也推出了標準的模塊 加載方案,經過export和import來導出和導入模塊。

  • 模塊化開發怎麼作

模塊化開發指的是在解決某一個複雜問題或者一系列問題時,依照一種分類的思惟把問題進行系統性的分解。模塊化是一種將複雜系統分解爲代碼結構更合理,可維護性更高的可管理的模塊方式。對於軟件行業:系統被分解爲一組高內聚,低耦合的模塊。
(1)定義封裝的模塊
(2)定義新模塊對其餘模塊的依賴
(3)可對其餘模塊的引入支持。在JavaScript中出現了一些非傳統模塊開發方式的規範。 CommonJS的模塊規範,AMD(Asynchronous Module Definition),CMD(Common Module Definition)等。AMD是異步模塊定義,全部的模塊將被異步加載,模塊加載不影響後邊語句運行。

  • 如何實現一個JS的AMD模塊加載器

AMD是解決JS模塊化的規範,實現這樣的一個模塊加載器的關鍵在於解決每一個模塊依賴的解析。首先咱們須要有一個模塊的入口,也就是主模塊,好比咱們使用 一個use方法做爲入口,以後以數組的形式列出了主模塊的依賴,這時候咱們要想到的是如何解析這一個一個的依賴,也就是如何解析出一個個js文件的絕對地址, 咱們能夠制定一個規則,如默認爲主模塊的路徑爲基準,也能夠像requirejs同樣使用一個config方法來指定一個baseurl和爲每個模塊指定一個path,最後就是 模塊的問題,咱們須要暴露一個define方法來定義模塊,也就是模塊名,依賴以及每一個模塊的各自代碼。其中每一個模塊的代碼都應該在依賴加載完以後執行,這就是一個 回調函數,模塊的依賴、回調函數、狀態、名字、模塊導出等能夠看作是一個模塊的屬性,所以咱們可使用一個對象來保存全部的模塊,而後每一個模塊的各個屬性存放在一個對象中。 最後咱們來考慮一下模塊加載的問題,上面咱們說到use方法,use方法的邏輯就是遍歷依賴,而後對每一個模塊進行加載,也就是解析地址而後使用插入script,咱們假設 使用loadModule方法來加載依賴,那麼這個函數的邏輯就應該是檢查咱們的模塊是否已經加載過來判斷是否須要加載,若是這個模塊還有依賴則調用use方法繼續解析,模塊依賴中咱們 尚未提到的問題就是每一個模塊的依賴是須要被傳進模塊裏來使用的,解決方法就是每一個模塊的callback方法執行後的返回的export記錄下來而後使用apply之類的方法將這些參數傳遞進去。 大體就是這樣子的。

參考:
動手實現一個AMD模塊加載器(一)
動手實現一個AMD模塊加載器(二)
動手實現一個AMD模塊加載器(三)

防抖和節流

函數節流就是讓一個函數沒法在很短的時間間隔內連續調用,而是間隔一段時間執行,這在咱們爲元素綁定一些事件的時候常常會用到,好比咱們 爲window綁定了一個resize事件,若是用戶一直改變窗口大小,就會一直觸發這個事件處理函數,這對性能有很大影響。
什麼是函數節流?
前端面試查漏補缺--(一) 防抖和節流

函數執行改變this

  • 談談對this對象的理解

1) this老是指向函數的直接調用者(而非間接調用者)
2) 若是有new關鍵字,this指向new出來的那個對象
3) 在事件中,this指向目標元素,特殊的是IE的attachEvent中的this老是指向全局對象window。

ES6/ES7

  • 簡要介紹ES6

ES6在變量的聲明和定義方面增長了let、const聲明變量,有局部變量的概念,賦值中有比較吸引人的結構賦值,同時ES6對字符串、 數組、正則、對象、函數等拓展了一些方法,如字符串方面的模板字符串、函數方面的默認參數、對象方面屬性的簡潔表達方式,ES6也 引入了新的數據類型symbol,新的數據結構set和map,symbol能夠經過typeof檢測出來,爲解決異步回調問題,引入了promise和 generator,還有最爲吸引人了實現Class和模塊,經過Class能夠更好的面向對象編程,使用模塊加載方便模塊化編程,固然考慮到 瀏覽器兼容性,咱們在實際開發中須要使用babel進行編譯。

  • let、const、var的使用區別

let: 至關於var,用於聲明一個變量,在塊級做用域有效(可解決for循環問題);不能重複聲明;不會變量提高;不會預處理
const: 用於定義一個常量,不能修改,其餘特色等同於let,用於保存不用改變的數據

  • Map與普通對象的區別

JavaScript 的對象(Object),本質上是鍵值對的集合(Hash 結構),可是傳統上只能用字符串看成鍵。這給它的使用帶來了很大的限制。爲了解決這個問題,ES6 提供了 Map 數據結構。它相似於對象,也是鍵值對的集合,可是「鍵」的範圍不限於字符串,各類類型的值(包括對象)均可以看成鍵。也就是說,Object 結構提供了「字符串—值」的對應,Map 結構提供了「值—值」的對應,是一種更完善的 Hash 結構實現。若是你須要「鍵值對」的數據結構,Map 比 Object 更合適。

AST

babel編譯原理

函數柯里化

數組

  • 判斷數組
Array.isArray([]);  // true
Array.isArray(undefined); // false;

或者
array instanceof Array; // true 檢測對象的原型鏈是否指向構造函數的prototype對象
或者
array.constructor === Array; // true

終極大招:
if (!Array.isArray) {
  Array.isArray = function(arg) {
    return Object.prototype.toString.call(arg) === '[object Array]';
  };
}

注意:typeof []; // "object" 不能夠用此方法檢查!!!

null,undefined的區別

null表示一個對象被定義了,但存放了空指針,轉換爲數值時爲0。
undefined表示聲明的變量未初始化,轉換爲數值時爲NAN。
typeof(null) -- object;
typeof(undefined) -- undefined

["1", "2", "3"].map(parseInt) 答案是多少

[1,NaN,NaN]

解析:
Array.prototype.map()
array.map(callback[, thisArg])
callback函數的執行規則
參數:自動傳入三個參數
currentValue(當前被傳遞的元素);
index(當前被傳遞的元素的索引);
array(調用map方法的數組)

parseInt方法接收兩個參數
第三個參數["1", "2", "3"]將被忽略。parseInt方法將會經過如下方式被調用
parseInt("1", 0)
parseInt("2", 1)
parseInt("3", 2)

parseInt的第二個參數radix爲0時,ECMAScript5將string做爲十進制數字的字符串解析;
parseInt的第二個參數radix爲1時,解析結果爲NaN;
parseInt的第二個參數radix在2—36之間時,若是string參數的第一個字符(除空白之外),不屬於radix指定進制下的字符,解析結果爲NaN。
parseInt("3", 2)執行時,因爲"3"不屬於二進制字符,解析結果爲NaN。

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

IE爲事件冒泡,Firefox同時支持事件捕獲和事件冒泡。但並不是全部瀏覽器都支持事件捕獲。jQuery中使用event.stopPropagation()方法可阻止冒泡;(舊IE的方法 ev.cancelBubble = true;)

如何阻止事件冒泡和默認事件?
標準的DOM對象中可使用事件對象的stopPropagation()方法來阻止事件冒泡,但在IE8如下中IE的事件對象經過設置事件對象的cancelBubble屬性爲true來阻止冒泡; 默認事件的話經過事件對象的preventDefault()方法來阻止,而IE經過設置事件對象的returnValue屬性爲false來阻止默認事件。

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

除了正常模式運行外,ECMAscript添加了第二種運行模式:「嚴格模式」。
做用:
1) 消除js不合理,不嚴謹地方,減小怪異行爲
2) 消除代碼運行的不安全之處,
3) 提升編譯器的效率,增長運行速度
4) 爲將來的js新版本作鋪墊。

對JSON的瞭解

全稱:JavaScript Object NotationJSON中對象經過「{}」來標識,一個「{}」表明一個對象,如{「AreaId」:」123」},對象的值是鍵值對的形式(key:value)。JSON是JS的一個嚴格的子集,一種輕量級的數據交換格式,相似於xml。數據格式簡單,易於讀寫,佔用帶寬小。兩個函數:JSON.parse(str)解析JSON字符串 把JSON字符串變成JavaScript值或對象JSON.stringify(obj) 將一個JavaScript值(對象或者數組)轉換爲一個 JSON字符串eval('('+json+')') 用eval方法注意加括號 並且這種方式更容易被攻擊

相關文章
相關標籤/搜索