刷面經筆記2019.02.11

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

三者均可以把一個函數應用到其餘對象上,apply,call是直接執行函數調用,bind是綁定,執行須要再次調用。  html

apply和call的區別是apply接受數組做爲參數,而call是接受逗號分隔的無限多個參數列表。前端

代碼以下:vue

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,isEnumerable都是作什麼用的?java

Object.defineProperty(obj,prop,descriptor)用來給對象定義屬性,有value,writeable,enumerable,set/get等,node

hasOwnProperty用於檢查某一屬性是否是存在於對象自己,react

isEnumerable用來檢測某一屬性是否可遍歷,也就是能不能用for...in循環來取到。git

 

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

 // 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.字符串經常使用的十個函數ajax

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上(Parement.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的理解

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

 

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(銷燬後)在實例銷燬以後調用。調用後,全部的事件監聽器會被移除,全部的子實例也會被銷燬。該鉤子在服務器端渲染期間不被調用。

 

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

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

 

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

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

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

 

11.使用npm有哪些好處?

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

 

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

use strict 是一種在JavaScript代碼運行時自動實行更嚴格解析和錯誤處理的方法。(嚴格模式)

將值分配給一個未聲明的變量會自動建立該名稱的全局變量。這是JavaScript中最多見的錯誤之一。在嚴格模式下,這樣作的話會拋出錯誤。消除 this 強制。

當檢測到對象(例如,var object = {foo: "bar", foo: "baz"};)中重複命名的屬性,或檢測到函數中(例如,function foo(val1, val2, val1){})重複命名的參數時,嚴格模式會拋出錯誤,所以捕捉幾乎能夠確定是代碼中的bug能夠避免浪費大量的跟蹤時間。使eval() 更安全。

 

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

與AngularJS的區別
相同點:
都支持指令:內置指令和自定義指令。
都支持過濾器:內置過濾器和自定義過濾器。
都支持雙向數據綁定。
都不支持低端瀏覽器。

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


與React的區別

相同點:
React採用特殊的JSX語法,Vue.js在組件開發中也推崇編寫.vue特殊文件格式,對文件內容都有一些約定,二者都須要編譯後使用。
中心思想相同:一切都是組件,組件實例之間能夠嵌套。
都提供合理的鉤子函數,可讓開發者定製化地去處理需求。
都不內置列數AJAX,Route等功能到核心包,而是以插件的方式加載。
在組件開發中都支持mixins的特性。

不一樣點:
React依賴Virtual DOM,而Vue.js使用的是DOM模板。React採用的Virtual DOM會對渲染出來的結果作髒檢查。
Vue.js在模板中提供了指令,過濾器等,能夠很是方便,快捷地操做Virtual DOM。

 

14.<keep-alive></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 engineer或Rendering Engine)和JS引擎。
渲染引擎:負責取得網頁的內容(HTML、XML、圖像等等)、
整理訊息(例如加入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;
}
相關文章
相關標籤/搜索