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排序方法總結。
10.8、 字串擴充套件了哪些方法?
1.codePointAt() 引數:字元在字串中的位置;返回值:返回一個字元的碼點
2.String.fromCodePoint() 引數:碼點 返回值:碼點對應的字元
3.for....of 字串的遍歷器介面
4.nomalize() 功能:將字元的不同表示方法統一為同樣的形式,稱之為Unicode正規化。引數:指定normalize的方式。
5.includes()功能:字串中是否含有子串; 引數:要查詢的子串 ;返回值:布林值,true或false。
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與解析如