前端常見面試題少量總結

lsj1992g發表於2019-03-14

原筆記地址

1、什麼是Promise?

Promise可以幫助我們更好地處理非同步操作。

new Promise((resolve, reject) =>
  {
     setTimeout(() =>
      {
          resolve('result');
      }, 100)
  })
  .then(console.log)
  .catch(console.error);
  
複製程式碼

2、async awite 是什麼?執行時機呢

    async function testSometing () {
      console.log('2執行testSometing')
      return 'testSometing'
    }
    async function testAsync () {
      console.log('6執行testAsync')
      return Promise.resolve('hello async')
    };
    async function test () {
      console.log('1 test start...')
      const v1 = await testSometing()
      console.log(v1 + '5') // 5
      const v2 = await testAsync()
      console.log(v2 + '8') // 8
      console.log(v1, v2 + '9') // 9
    };
    test()
    let promise = new Promise(resolve => {
      const a = {}
      const b = JSON.parse(a)
      console.log('3promise start..')
      resolve(b)
    })
    promise.then(val => console.log(val)).catch(err =>      console.log(err)) // 7
    console.log('4test end...')
熟悉promise 和 async/awite 異同:
都是解決js非同步回撥問題,promise內部無法進行try catch 只能使用原型上的catch方式統一進行程式碼捕獲,而且promise內部無法進行斷點除錯。 async/awite 內部可以try catch可以斷點。

複製程式碼

3、ES6 set map 函式

const set = new Set([1, 2, 3, 4, 4]);
[...set]

上面程式碼通過add方法向 Set 結構加入成員,結果表明Set 結構不會新增重複的值

陣列去重:
方法一:
[...new Set(array)]
方法二:
function dedupe(array) {
  return Array.from(new Set(array));
}
 
dedupe([1, 1, 2, 3]) // [1, 2, 3]

將類陣列物件轉換成陣列:

let arrayLike = {
    0: 'tom', 
    1: '65',
    2: '男',
    3: ['jane','john','Mary'],
    'length': 4
}
let arr = Array.from(arrayLike)
console.log(arr) // ['tom','65','男',['jane','john','Mary']]
要將一個類陣列物件轉換為一個真正的陣列,必須具備以下條件:
1、該類陣列物件必須具有length屬性,用於指定陣列的長度。如果沒有length屬性,那麼轉換後的陣列是一個空陣列。
2、該類陣列物件的屬性名必須為數值型或字串型的數字
複製程式碼

ps: 該類陣列物件的屬性名可以加引號,也可以不加引號

3.1 set 方法


add(value):新增某個值,返回Set結構本身。
delete(value):刪除某個值,返回一個布林值,表示刪除是否成功。
has(value):返回一個布林值,表示該值是否為Set的成員。
clear():清除所有成員,沒有返回值

keys():返回鍵名的遍歷器
values():返回鍵值的遍歷器
entries():返回鍵值對的遍歷器
forEach():使用回撥函式遍歷每個成員
擴充套件運算子(...)內部使用for...of迴圈,所以也可以用於 Set 結構。
使用 Set 可以很容易地實現並集(Union)、交集(Intersect)和差集(Difference)。

let a = new Set([1, 2, 3]);
let b = new Set([4, 3, 2]);
 
// 並集
let union = new Set([...a, ...b]);
// Set {1, 2, 3, 4}
 
// 交集
let intersect = new Set([...a].filter(x => b.has(x)));
// set {2, 3}
 
// 差集
let difference = new Set([...a].filter(x => !b.has(x)));




複製程式碼

3.2 MAP方法:

Map有size()屬性,檢視Map物件大小,set(key , value) , get(Key), delete(key) , has(key) ,clear()方法。
遍歷方法
Map 結構原生提供三個遍歷器生成函式和一個遍歷方法。

keys():返回鍵名的遍歷器。
values():返回鍵值的遍歷器。
entries():返回所有成員的遍歷器。
複製程式碼

forEach():遍歷 Map 的所有成員。

4、 閉包、原型鏈等概念的理解

4.1、什麼是閉包


《高階程式設計》上,這樣說:當在函式內部定義了其他函式時候,就建立了閉包。閉包有權訪問包含函式內部的所有變數。通俗的說,閉包就是作用域範圍,因為js是函式作用域,所以函式就是閉包.更多的應用其實是在內嵌函式,這就會涉及到內嵌作用域,也叫作用域鏈.如果子作用域裡的函式引用了父作用域的函式,這就會帶來另外一個問題,什麼時候引用結束?如果不結束,就會一直佔用記憶體,過多引用會引起記憶體洩漏。

複製程式碼

4.2、對原型鏈的理解

當呼叫某種方法或查詢某種屬性時,首先會在自身呼叫和查詢,如果自身並沒有該屬性或方法,則會去它的__proto__屬性中呼叫查詢,也就是它建構函式的prototype中呼叫查詢。
由於__proto__是任何物件都有的屬性,而js裡萬物皆物件,所以會形成一條__proto__連起來的鏈條,遞迴訪問__proto__必須最終訪問到頭,並且值為null。

複製程式碼

1.查詢屬性,如果本身沒有,則會去__proto__中查詢,也就是建構函式的顯式原型中查詢,如果建構函式中也沒有該屬性,因為建構函式也是物件,也有__proto__,那麼會去它的顯式原型中查詢,一直到null,如果沒有則返回undefined

2.p.proto.constructor  == function Person(){}

3.p._proto.proto== Object.prototype

4.proto

5.通過__proto__形成原型鏈而非protrotype

利用原型讓一個引用型別繼承另一個引用型別的屬性和方法。

每個建構函式都有一個原型物件,原型物件都包含一個指向建構函式的指標(constructor),而例項物件都包含一個指向原型物件的內部指標(__proto__)。
如果讓原型物件等於另一個型別的例項,此時的原型物件將包含一個指向另一個原型的指標(__proto__),另一個原型也包含著一個指向另一個建構函式的指標(constructor)。假如另一個原型又是另一個型別的例項……這就構成了例項與原型的鏈條。


複製程式碼

圖解:

圖片
圖片

5 、JS繼承的實現方式?

拷貝自www.cnblogs.com/humin/p/455…文章。

// 定義一個動物類
function Animal (name) {
  // 屬性
  this.name = name || 'Animal';
  // 例項方法
  this.sleep = function(){
    console.log(this.name + '正在睡覺!');
  }
}
// 原型方法
Animal.prototype.eat = function(food) {
  console.log(this.name + '正在吃:' + food);
};

複製程式碼

5.1 原型鏈繼承


function Cat(){ 
}
Cat.prototype = new Animal(); // 關鍵程式碼
Cat.prototype.name = 'cat';

// Test Code
var cat = new Cat();
console.log(cat.name); // cat
console.log(cat.eat('fish')); // cat正在吃:fish
console.log(cat.sleep());//cat正在睡覺!
console.log(cat instanceof Animal); //true 
console.log(cat instanceof Cat); //true

特點:
非常純粹的繼承關係,例項是子類的例項,也是父類的例項
父類新增原型方法/原型屬性,子類都能訪問到
簡單,易於實現

缺點:
要想為子類新增屬性和方法,必須要在new Animal()這樣的語句之後執行,不能放到構造器中
無法實現多繼承
來自原型物件的引用屬性是所有例項共享的
建立子類例項時,無法向父類建構函式傳參


複製程式碼

5.2、構造繼承

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name); // Tom
console.log(cat.sleep()); // Tom正在睡覺!
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true
特點:
解決了原型鏈繼承中,子類例項共享父類引用屬性的問題
建立子類例項時,可以向父類傳遞引數
可以實現多繼承(call多個父類物件)

缺點:
例項並不是父類的例項,只是子類的例項
只能繼承父類的例項屬性和方法,不能繼承原型屬性/方法
無法實現函式複用,每個子類都有父類例項函式的副本,影響效能

複製程式碼

5.3、例項繼承

function Cat(name){
  var instance = new Animal();
  instance.name = name || 'Tom';
  return instance;
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // false

特點:
不限制呼叫方式,不管是new 子類()還是子類(),返回的物件具有相同的效果

缺點:
例項是父類的例項,不是子類的例項
不支援多繼承


複製程式碼

5.4、拷貝繼承

function Cat(name){
  var animal = new Animal();
  for(var p in animal){
    Cat.prototype[p] = animal[p];
  }
  Cat.prototype.name = name || 'Tom';
}

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // false
console.log(cat instanceof Cat); // true

特點:
支援多繼承

缺點:
效率較低,記憶體佔用高(因為要拷貝父類的屬性)
無法獲取父類不可列舉的方法(不可列舉方法,不能使用for in 訪問到)

複製程式碼

5.5、組合繼承

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
Cat.prototype = new Animal();

// 組合繼承也是需要修復建構函式指向的。

Cat.prototype.constructor = Cat;

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); // true

特點:
彌補了 構造繼承 的缺陷,可以繼承例項屬性/方法,也可以繼承原型屬性/方法
既是子類的例項,也是父類的例項
不存在引用屬性共享問題
可傳參
函式可複用

缺點:
呼叫了兩次父類建構函式,生成了兩份例項(子類例項將子類原型上的那份遮蔽了)

複製程式碼

6.6 、寄生組合繼承

function Cat(name){
  Animal.call(this);
  this.name = name || 'Tom';
}
(function(){
  // 建立一個沒有例項方法的類
  var Super = function(){};
  Super.prototype = Animal.prototype;
  //將例項作為子類的原型
  Cat.prototype = new Super();
  Cat.prototype.constructor = Cat;

})();

// Test Code
var cat = new Cat();
console.log(cat.name);
console.log(cat.sleep());
console.log(cat instanceof Animal); // true
console.log(cat instanceof Cat); //true

複製程式碼

6、常用js方法

6.1 陣列去重

陣列去重:
//方法一:
Array.prototype.unique = function(){
    var result = [];
    this.forEach(function(v){
        if(result.indexOf(v) < 0){
            result.push(v);
        }
    });
    return result;
}
//方法二:
Array.prototype.unique = function(){
    var result = [],hash = {};
    this.forEach(function(v){
        if(!hash[v]){
          hash[v] = true;
          result.push(v);
        }
    });
    return result;
}
//方法二存在隱式轉換比如 1 和 "1" 會被認為是重複,所以進行升級:
Array.prototype.unique = function(){
    var result = [],hash = {};
    this.forEach(function(v){
        var type = typeof(v);  //獲取元素型別
        hash[v] || (hash[v] = new Array());
        if(hash[v].indexOf(type) < 0){
            hash[v].push(type);  //儲存型別
            result.push(v);
        }
    });
    return result;
}
//方法四:先排序再去重
Array.prototype.unique = function(){
  var result = [this[0]];
  this.sort();
  this.forEach(function(v){
    v != result[result.length - 1] && result.push(v); //僅與result最後一個元素比較
  });
}
// es6 去重:方法一
Array.prototype.unique = function(){
   return [...new Set(this)];
}
// es6 去重:方法二
Array.prototype.unique = function(){
  return Array.form(new Set(this))
}

//排序演算法

複製程式碼

6.2、 計算出下面字串出現次數最多的值?

let str = 'abcdefghigakgjisaaaganghegsa'
function getMaxVal(str) {
  let strArr = [...str]
  let max = 0
  let obj = {}
  let maxVal = ''
  strArr.forEach(function(item, i){
    obj[item] = obj[item] == 'undefined'? 1 : obj[item] + 1
    if(obj[item] > max) {
      max = obj[item]
      maxVal = item
    }
  })
  return maxVal
}

複製程式碼

6.3、 翻轉字串

let str = 'hello lsj'
function reverseStr (str) {
  return [...str].reverse().join('')
}

複製程式碼

6.4、 翻轉字串

let str = 'hello lsj'
function reverseStr (str) {
  return [...str].reverse().join('')
}
複製程式碼

7、async和defer的區別

都是為script增減屬性,它定義指令碼是否非同步執行。async 屬性僅適用於外部指令碼(只有在使用 src 屬性時)有多種執行外部指令碼的方法:

· 如果 async="async":指令碼相對於頁面的其餘部分非同步地執行(當頁面繼續進行解析時,指令碼將被執行)

· 如果不使用 async 且 defer="defer":指令碼將在頁面完成解析時執行

· 如果既不使用 async 也不使用 defer:在瀏覽器繼續解析頁面之前,立即讀取並執行指令碼

· 為html元素增加manifest,開發離線web應用程式時他與API結合使用,定義一個URL,在這個URL上描述文件的快取資訊。

· 為iframe增加撒個屬性,sandbox、seamless、srcdoc。用來提高頁面安全性,防止不信任的web頁面執行某些操作。

複製程式碼

8、前端快取機制和辦法

9、node面試題

9.1、Cookies如何防範XSS攻擊

XSS(Cross-Site Scripting,跨站指令碼攻擊)是指攻擊者在返回的HTML中插入JavaScript指令碼。為了減輕這些攻擊,需要在HTTP頭部配置set-cookie:

HttpOnly - 這個屬性可以防止cross-site scripting,因為它會禁止Javascript指令碼訪問cookie。
secure - 這個屬性告訴瀏覽器僅在請求為HTTPS時傳送cookie。

複製程式碼

10、js基礎查漏補缺。

參考https://www.cnblogs.com/meteorcn/p/node_mianshiti_interview_question.html
複製程式碼

10.1、apply, call和bind有什麼區別?

三者都可以把一個函式應用到其他物件上,注意不是自身物件也就是用來改變this指向.apply,call是直接執行函式呼叫,bind是繫結,執行需要再次呼叫.apply和call的區別是apply接受陣列作為引數,而call是接受逗號分隔的無限多個引數列表
複製程式碼

10.2、** caller, callee和arguments分別是什麼?**

caller, callee之間的關係就像是employer和employee之間的關係,就是呼叫與被呼叫的關係,二者返回的都是函式物件引用.arguments是函式的所有引數列表,它是一個類陣列的變數.

複製程式碼

10.3、defineProperty, hasOwnProperty, isEnumerable都是做什麼用的?

Object.defineProperty(obj, prop, descriptor)用來給物件定義屬性,有value,writable,configurable,enumerable,set/get等.
hasOwnProerty用於檢查某一屬性是不是存在於物件本身,繼承來的父親的屬性不算.isEnumerable用來檢測某一屬性是否可遍歷,也就是能不能用for..in迴圈來取到

複製程式碼

10.4、列舉陣列相關的常用方法

push/pop, 
shift/unshift, 
split/join, 
slice/splice/concat, 
sort/reverse, 
map/reduce, 
forEach, filter

複製程式碼

10.5、 列舉字串相關的常用方法

 indexOf/lastIndexOf/charAt, 
 split/match/test,
 slice/substring/substr, 
 toLowerCase/toUpperCase
enctype="multipart/form-data" method="post"
複製程式碼

10.6、 檔案上傳需要設定什麼?

 
enctype="multipart/form-data" method="post"
複製程式碼

10.7、js排序方法總結。

js排序方法彙總.js

10.8、 字串擴充套件了哪些方法?

1.codePointAt() 引數:字元在字串中的位置;返回值:返回一個字元的碼點

2.String.fromCodePoint() 引數:碼點 返回值:碼點對應的字元

3.for....of     字串的遍歷器介面

4.nomalize() 功能:將字元的不同表示方法統一為同樣的形式,稱之為Unicode正規化。引數:指定normalize的方式。

5.includes()功能:字串中是否含有子串; 引數:要查詢的子串 ;返回值:布林值,truefalse。

6.startsWith()返回值:布林型別,表示字串是否在源字串的頭部;當有第二個引數時,表示開始搜尋的位置。

7.endsWith()返回值:布林型別,表示字串是否在源字串的尾部。當有第二個引數時,表示開始搜尋的位置。

8.repeat():返回值:將源字串重複n次。引數:字串重複次數。

9.padStart()功能:如果字串不夠指定長度,會在頭部補全。引數:第一個指定長度,第二個指定字串。返回值:返回新的字串

10.padEnd()同上,不過是在尾部

11.String.raw() 功能:用來充當模板字串的處理函式。返回值:斜槓都被轉義的字串。


複製程式碼

JavaScript 非同步、棧、事件迴圈、任務佇列

圖片
Js 中,有兩類任務佇列:巨集任務佇列(macro tasks)和微任務佇列(micro tasks)。巨集任務佇列可以有多個,微任務佇列只有一個。那麼什麼任務,會分到哪個佇列呢?

  • 巨集任務:script(全域性任務), setTimeout, setInterval, setImmediate, I/O, UI rendering.
  • 微任務:process.nextTick, Promise, Object.observer, MutationObserver.

瀏覽器的 Event Loop

瀏覽器的 Event Loop 遵循的是 HTML5 標準,而 NodeJs 的 Event Loop 遵循的是 libuv。 區別較大.


複製程式碼

網站效能優化中有一條:dns與解析如

相關文章