刷前端面經筆記(八)

1.apply,call,bind有什麼區別?

三者均可以把一個函數應用到其餘對象上,apply,call是直接執行函數調用,bind是綁定,執行須要再次調用。
applycall的區別是apply接受數組做爲參數,而call是接受逗號分隔的無限多個參數列表。
代碼以下:javascript

function Person() {
    }
    Person.prototype.sayName() { alert(this.name); }

    var obj = {name: 'michaelqin'}; // 注意這是一個普通對象,它不是Person的實例
    // 1) apply
    Person.prototype.sayName.apply(obj, [param1, param2, param3]);

    // 2) call
    Person.prototype.sayName.call(obj, param1, param2, param3);

    // 3) bind
    var liaoke = Person.prototype.sayName.bind(obj);    
    liaoke ([param1, param2, param3]); // bind須要先綁定,再執行 
    liaoke (param1, param2, param3); // bind須要先綁定,再執行

2.介紹一下defineProperty,hasOwnProperty, propertyIsEnumerable

Object.defineProperty(obj,prop,descriptor)用來給對象定義屬性,有value,writeable,enumerable,set/get,configurable
hasOwnProperty用於檢查某一屬性是否是存在於對象自己,
propertyIsEnumerable用來檢測某一屬性是否可遍歷,也就是能不能用for...in循環來取到。html

3.JS經常使用設計模式的實現思路(單例、工廠、代理、裝飾、觀察者模式等)

// 1) 單例: 任意對象都是單例,無須特別處理
    var obj = {name: 'michaelqin', age: 30};

 // 2) 工廠: 就是一樣形式參數返回不一樣的實例
    function Person() { this.name = 'Person1'; }
    function Animal() { this.name = 'Animal1'; }

    function Factory() {}
    Factory.prototype.getInstance = function(className) {
        return eval('new ' + className + '()');
    }

    var factory = new Factory();
    var obj1 = factory.getInstance('Person');
    var obj2 = factory.getInstance('Animal');
    console.log(obj1.name); // Person1
    console.log(obj2.name); // Animal1

 // 3) 代理: 就是新建個類調用老類的接口,包一下
    function Person() { }
    Person.prototype.sayName = function() { console.log('michaelqin'); }
    Person.prototype.sayAge = function() { console.log(30); }

    function PersonProxy() { 
        this.person = new Person();
        var that = this;
        this.callMethod = function(functionName) {
            console.log('before proxy:', functionName);
            that.person[functionName](); // 代理
            console.log('after proxy:', functionName);
        }
    }

    var pp = new PersonProxy();
    pp.callMethod('sayName'); // 代理調用Person的方法sayName()
    pp.callMethod('sayAge'); // 代理調用Person的方法sayAge() 

  // 4) 觀察者: 就是事件模式,好比按鈕的onclick這樣的應用.
    function Publisher() {
        this.listeners = [];
    }
    Publisher.prototype = {
        'addListener': function(listener) {
            this.listeners.push(listener);
        },

        'removeListener': function(listener) {
            delete this.listeners[listener];
        },

        'notify': function(obj) {
            for(var i = 0; i < this.listeners.length; i++) {
                var listener = this.listeners[i];
                if (typeof listener !== 'undefined') {
                    listener.process(obj);
                }
            }
        }
    }; // 發佈者

    function Subscriber() {

    }
    Subscriber.prototype = {
        'process': function(obj) {
            console.log(obj);
        }
    }; // 訂閱者

    var publisher = new Publisher();
    publisher.addListener(new Subscriber());
    publisher.addListener(new Subscriber());
    publisher.notify({name: 'michaelqin', ageo: 30}); // 發佈一個對象到全部訂閱者
    publisher.notify('2 subscribers will both perform process'); // 發佈一個字符串到全部訂閱者

3.處理字符串經常使用的十個函數

charAt()   // 返回在指定位置的字符。
concat()   // 鏈接字符串。
fromCharCode()   // 從字符編碼建立一個字符串。
indexOf()  // 檢索字符串。
match()   // 找到一個或多個正則表達式的匹配。
replace()   // 替換與正則表達式匹配的子串。
search()   // 檢索與正則表達式相匹配的值。
slice()   // 提取字符串的片段,並在新的字符串中返回被提取的部分。
split()   // 把字符串分割爲字符串數組。
substr()   // 從起始索引號提取字符串中指定數目的字符。
substring()   // 提取字符串中兩個指定的索引號之間的字符。
toLocaleLowerCase()   // 把字符串轉換爲小寫。
toLocaleUpperCase()   // 把字符串轉換爲大寫。
toLowerCase()   // 把字符串轉換爲小寫。
toUpperCase()   // 把字符串轉換爲大寫。
toString()   // 返回字符串。
valueOf()   // 返回某個字符串對象的原始值。

4.如何判斷一個變量是對象仍是數組

function isObjArr(variable){
     if (Object.prototype.toString.call(value) === "[object Array]") {
            console.log('value是數組');
       }else if(Object.prototype.toString.call(value)==='[object Object]'){//這個方法兼容性好一點
            console.log('value是對象');
      }else{
          console.log('value不是數組也不是對象')
      }
}

// 注意:千萬不能使用typeof來判斷對象和數組,由於這兩種類型都會返回"object"。

5.ES5的繼承和ES6的繼承有什麼區別?

ES5的繼承是經過prototype或構造函數機制來實現。
ES5的繼承實質上是先建立子類的實例對象,而後再將父類的方法添加到this上(Parent.apply(this))。
ES6的繼承機制實質上是先建立父類的實例對象this(因此必須先調用父類的super()方法),而後再用子類的構造函數修改this。具體爲ES6經過class關鍵字定義類,裏面有構造方法,類之間經過extends關鍵字實現繼承。子類必須在constructor方法中調用super方法,不然新建實例報錯。由於子類沒有本身的this對象,而是繼承了父類的this對象,而後對其調用。若是不調用super方法,子類得不到this對象。前端

注意:super關鍵字指代父類的實例,即父類的this對象。在子類構造函數中,調用super後,纔可以使用this關鍵字,不然報錯。

6.下面的ul,如何點擊每一列的時候alert其index?(閉包)

<ul id="test">
 <li>這是第一條</li>
 <li>這是第二條</li>
 <li>這是第三條</li>
 </ul>


// 方法一:
var lis=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=function(){
alert(this.index);
};
}

//方法二:
var lis=document.getElementById('test').getElementsByTagName('li');
for(var i=0;i<3;i++)
{
lis[i].index=i;
lis[i].onclick=(function(a){
return function() {
alert(a);
}
})(i);
}

7.對於MVVM的理解

MVVMModel-View-ViewModel 的縮寫。
Model表明數據模型,也能夠在Model中定義數據修改和操做的業務邏輯。
View 表明UI 組件,它負責將數據模型轉化成UI 展示出來。
ViewModel 監聽模型數據的改變和控制視圖行爲、處理用戶交互,
簡單理解就是一個同步View Model的對象,鏈接ModelView
MVVM架構下,View Model 之間並無直接的聯繫,
而是經過ViewModel進行交互,ModelViewModel 之間的交互是雙向的,
所以View 數據的變化會同步到Model中,而Model 數據的變化也會當即反應到View 上。
ViewModel 經過雙向數據綁定把 View 層和 Model 層鏈接了起來,
ViewModel 之間的同步工做徹底是自動的,無需人爲干涉,
所以開發者只需關注業務邏輯,不須要手動操做DOM,
不須要關注數據狀態的同步問題,
複雜的數據狀態維護徹底由 MVVM 來統一管理。vue

8.解釋Vue的生命週期

Vue實例從建立到銷燬的過程,就是生命週期。從開始建立、初始化數據、編譯模板、掛載Dom->渲染、更新->渲染、銷燬等一系列過程,稱之爲 Vue的生命週期。

Vue的生命週期包括:
beforeCreate(建立前)在數據觀測和初始化事件還未開始,
created(建立後)完成數據觀測,屬性和方法的運算,初始化事件,$el屬性尚未顯示出來;
beforeMount(載入前)在掛載開始以前被調用,相關的render函數首次被調用,實例已完成如下的配置:編譯模板,把data裏面的數據和模板生成html,注意此時尚未掛載html到頁面上;
mounted(載入後)在el被新建立的vm.$el替換,並掛載到實例上去以後調用,實例已完成如下配置:用上面編譯好的html內容替換el屬性指向的DOM對象,完成模板中的html渲染到html頁面中,此過程當中進行ajax交互。
beforeUpdate(更新前)在數據更新以前調用,發生在虛擬DOM從新渲染和打補丁以前,能夠在該鉤子中進一步地更改狀態,不會觸發附加的重渲染過程。
updated(更新後)在因爲數據更改致使的虛擬DOM從新渲染和打補丁以後調用。調用時,組件DOM已經更新,因此能夠執行依賴於DOM的操做。然而在大多數狀況下,應該避免在此期間更改狀態,由於這可能會致使更新無限循環,該鉤子在服務器渲染期間不被調用。
beforeDestroy(銷燬前)在實例銷燬以前調用,實例仍然徹底可用。
destroyed(銷燬後)在實例銷燬以後調用。調用後,全部的事件監聽器會被移除,全部的子實例也會被銷燬。該鉤子在服務器端渲染期間不被調用。java

9.爲何使用Node.js,它有哪些優缺點?

優勢:
事件驅動,經過閉包很容易實現客戶端的生命活期。
不用擔憂多線程,鎖,並行計算的問題
V8引擎速度很是快
對於遊戲來講,寫一遍遊戲邏輯代碼,前端後端通用
缺點:
node.js更新很快,可能會出現版本兼容
node.js還不算成熟,尚未大製做
node.js不像其餘的服務器,對於不一樣的連接,不支持進程和線程操做node

10.什麼是錯誤優先的回調函數?

錯誤優先(Error-first)的回調函數(Error-First Callback)用於同時返回錯誤和數據。
第一個參數返回錯誤,而且驗證它是否出錯;其餘參數返回數據。react

fs.readFile(filePath, function(err, data)
{
    if (err)
    {
        // 處理錯誤
        return console.log(err);
    }
    console.log(data);
});

11.使用npm有哪些好處?

經過npm,你能夠安裝和管理項目的依賴,
而且可以指明依賴項的具體版本號。
對於Node應用開發而言,
能夠經過package.json文件來管理項目信息,
配置腳本,以及指明依賴的具體版本。git

12.在JavaScript源文件的開頭包含 use strict 有什麼意義和好處?

use strict 是一種在JavaScript代碼運行時自動實行更嚴格解析和錯誤處理的方法。(嚴格模式)
將值分配給一個未聲明的變量會自動建立該名稱的全局變量。這是JavaScript中最多見的錯誤之一。在嚴格模式下,這樣作的話會拋出錯誤。消除 this 強制。
當檢測到對象(例如,var object = {foo: "bar", foo: "baz"};)中重複命名的屬性,或檢測到函數中(例如,function foo(val1, val2, val1){})重複命名的參數時,嚴格模式會拋出錯誤,所以捕捉幾乎能夠確定是代碼中的bug能夠避免浪費大量的跟蹤時間。比eval() 更安全。angularjs

13.vuejs與angularjs以及react的區別?

AngularJS的區別
相同點:
都支持指令:內置指令和自定義指令。
都支持過濾器:內置過濾器和自定義過濾器。
都支持雙向數據綁定。
都不支持低端瀏覽器。
不一樣點:
1.AngularJS的學習成本高,好比增長了Dependency Injection特性,而Vue.js自己提供的API都比較簡單、直觀。
2.在性能上,AngularJS依賴對數據作髒檢查,因此Watcher越多越慢。
Vue.js使用基於依賴追蹤的觀察而且使用異步隊列更新。全部的數據都是獨立觸發的。
對於龐大的應用來講,這個優化差別仍是比較明顯的。ajax

React的區別
相同點:
React採用特殊的JSX語法,Vue.js在組件開發中也推崇編寫.vue特殊文件格式,對文件內容都有一些約定,二者都須要編譯後使用。
中心思想相同:一切都是組件,組件實例之間能夠嵌套。
都提供合理的鉤子函數,可讓開發者定製化地去處理需求。
都不內置列數AJAXRoute等功能到核心包,而是以插件的方式加載。
在組件開發中都支持mixins的特性。
不一樣點:
React依賴Virtual DOM,而Vue.js使用的是DOM模板。React採用的Virtual DOM會對渲染出來的結果作髒檢查。
Vue.js在模板中提供了指令,過濾器等,能夠很是方便,快捷地操做Virtual DOM

14.標籤keep-alive的做用是什麼?

<keep-alive></keep-alive> 包裹動態組件時,會緩存不活動的組件實例,主要用於保留組件狀態或避免從新渲染。

15.WeakMap 和 Map 的區別?

WeakMap 結構與 Map 結構基本相似,惟一的區別是它只接受對象做爲鍵名( null 除外),不接受其餘類型的值做爲鍵名,並且鍵名所指向的對象,不計入垃圾回收機制。
WeakMap 最大的好處是能夠避免內存泄漏。一個僅被 WeakMap 做爲 key 而引用的對象,會被垃圾回收器回收掉。
WeakMap 擁有和 Map 相似的 set(key, value)get(key)has(key)delete(key) clear() 方法, 沒有任何與迭代有關的屬性和方法。

16.http和https的基本概念?

http: 超文本傳輸協議,是互聯網上應用最爲普遍的一種網絡協議,是一個客戶端和服務器端請求和應答的標準(TCP),用於從WWW服務器傳輸超文本到本地瀏覽器的傳輸協議,它可使瀏覽器更加高效,使網絡傳輸減小。
https: 是以安全爲目標的HTTP通道,簡單講是HTTP的安全版,即HTTP下加入SSL層,HTTPS的安全基礎是SSL,所以加密的詳細內容就須要SSL
https協議的主要做用是:創建一個信息安全通道,來確保數組的傳輸,確保網站的真實性。

17.git fetch和git pull的區別?

git pull:至關因而從遠程獲取最新版本並merge到本地
git fetch:至關因而從遠程獲取最新版本到本地,不會自動merge

18.介紹一下對瀏覽器內核的理解?

主要分紅兩部分:渲染引擎(layout engineerRendering Engine)和JS引擎。
渲染引擎:負責取得網頁的內容(HTMLXML、圖像等等)、
整理訊息(例如加入CSS等),以及計算網頁的顯示方式,而後會輸出至顯示器或打印機。
瀏覽器的內核的不一樣對於網頁的語法解釋會有不一樣,因此渲染的效果也不相同。
全部網頁瀏覽器、電子郵件客戶端以及其它須要編輯、顯示網絡內容的應用程序都須要內核。
JS引擎:解析和執行javascript來實現網頁的動態效果。
最開始渲染引擎和JS引擎並無區分的很明確,後來JS引擎愈來愈獨立,內核就傾向於只指渲染引擎。

19.什麼是微格式

微格式(Microformats)是一種讓機器可讀的語義化XHTML詞彙的集合,是結構化數據的開放標準。
是爲特殊應用而制定的特殊格式
優勢:將智能數據添加到網頁上,讓網站內容在搜索引擎結果界面能夠顯示額外的提示。

20.數據綁定基本的實現

// 實現一個方法,能夠給 obj 全部的屬性添加動態綁定事件,當屬性值發生變化時會觸發事件
let obj = {
  key_1: 1,
  key_2: 2
}
function func(key) {
  console.log(key + ' 的值發生改變:' + this[key]);
}
bindData(obj, func);
obj.key_1 = 2; // 此時自動輸出 "key_1 的值發生改變:2"
obj.key_2 = 1; // 此時自動輸出 "key_2 的值發生改變:1"

答案:

function bindData(obj, fn) {
  for (let key in obj) {
    Object.defineProperty(obj, key, {
      set(newVal) {
        if (this.value !== newVal) {
          this.value = newVal;
          fn.call(obj, key);
        }
      },
      get() {
        return this.value;
      }
    })
  }
}

20.數據結構處理

// 有一個祖先樹狀 json 對象,當一我的有一個兒子的時候,其 child 爲其兒子對象,若是有多個兒子,child 爲兒子對象的數組。

請實現一個函數,找出這個家族中全部有多個兒子的人的名字(name),輸出一個數組。

列子:
// 樣例數據
let data = {
  name: 'jack',
  child: [
    { name: 'jack1' },
    {
      name: 'jack2',
      child: [{
        name: 'jack2-1',
        child: { name: 'jack2-1-1' }
      }, {
        name: 'jack2-2'
      }]
    },
    {
      name: 'jack3',
      child: { name: 'jack3-1' }
    }
  ]
}


// 答案:

// 用遞歸
function findMultiChildPerson(data) {
  let nameList = [];

  function tmp(data) {
    if (data.hasOwnProperty('child')) {
      if (Array.isArray(data.child)) {
        nameList.push(data.name);
        data.child.forEach(child => tmp(child));
      } else {
        tmp(data.child);
      }
    }
  }
  tmp(data);
  return nameList;
}

// 不用遞歸
function findMultiChildPerson(data) {
  let list = [data];
  let nameList = [];

  while (list.length > 0) {
    const obj = list.shift();
    if (obj.hasOwnProperty('child')) {
      if (Array.isArray(obj.child)) {
        nameList.push(obj.name);
        list = list.concat(obj.child);
      } else {
        list.push(obj.child);
      }
    }
  }
  return nameList;
}

歡迎關注

相關文章
相關標籤/搜索