https://github.com/ltadpolesjavascript
4. 數組對象有哪些經常使用方法nginx
7. 什麼是閉包,爲何要用它github
8. 介紹一下 JavaScript 原型,原型鏈,它們有何特色web
11. 同步和異步的區別,怎麼異步加載 JavaScript
14. apply()、call()和 bind() 是作什麼的,它們有什麼區別
22. export 與 export default有什麼區別
6種原始數據類型:
true
和 false
Null
類型只有一個值: null
,特指對象的值未設置undefined
引用類型:Object
typeof
操做符:返回一個字符串,表示未經計算的操做數的類型
typeof
操做符對於簡單數據類型,返回其自己的數據類型,函數對象返回function
,其餘對象均返回Object
null
返回Object
A instanceof B
,返回一個Boolean
類型的值
instanceof
檢測的是原型,只能用來判斷兩個對象是否屬於實例關係, 而不能判斷一個對象實例具體屬於哪一種類型
let a = []; a instanceof Array // true a instanceof Object // true
變量a 的
__proto__
直接指向Array.prototype
,間接指向Object.prototype
,因此按照instanceof
的判斷規則,a 就是Object
的實例.針對數組的這個問題,ES5 提供了Array.isArray()
方法 。該方法用以確認某個對象自己是否爲 Array 類型
prototype
原型,而後再在 prototype
上添加一個 constructor
屬性,並讓其指向該函數的引用
null
和undefined
是無效的對象,所以是不會有constructor
存在的,這兩種類型的數據須要經過其餘方式來判斷
函數的
constructor
是不穩定的,這個主要體如今自定義對象上,當開發者重寫prototype
後,原有的constructor
引用會丟失,constructor
會默認爲Object
function F() {}; var f = new F; f.constructor == F // true F.prototype = {a: 1} var f = new F f.constructor == F // false
在構造函數
F.prototype
沒有被重寫以前,構造函數F
就是新建立的對象f
的數據類型。當F.prototype
被重寫以後,原有的constructor
引用丟失, 默認爲 Object
所以,爲了規範開發,在重寫對象原型時通常都須要從新給
constructor
賦值,以保證對象實例的類型不被篡改
Object
的原型方法,調用該方法,默認返回當前對象的 [[Class]]
。這是一個內部屬性,其格式爲 [object Xxx]
,其中 Xxx
就是對象的類型Object.prototype.toString.call('') ; // [object String] Object.prototype.toString.call(11) ; // [object Number] Object.prototype.toString.call(true) ; // [object Boolean] Object.prototype.toString.call(Symbol()); //[object Symbol] Object.prototype.toString.call(undefined) ; // [object Undefined] Object.prototype.toString.call(null) ; // [object Null] Object.prototype.toString.call(new Function()) ; // [object Function] Object.prototype.toString.call([]) ; // [object Array]
null
表示"沒有對象",即該處不該該有值
典型用法:
undefined
表示"缺乏值",就是此處應該有一個值,可是尚未定義
典型用法:
undefined
undefined
undefined
undefined
修改器方法:
訪問方法:
迭代方法:
undefined
true
,不然返回 falsetrue
,不然返回 falsetrue
的數組元素放進一個新數組中並返回更多方法請參考 MDN 傳送門
對象字面量
var obj = {}
Object 構造函數
var obj = new Object()
工廠模式
function Person(name, age) { var o = new Object() o.name = name; o.age = age; o.say = function() { console.log(name) } return o }
缺點: 每次經過Person
建立對象的時候,全部的say
方法都是同樣的,可是卻存儲了屢次,浪費資源
構造函數模式
function Person(name, age) { this.name = name this.age = age this.say = function() { console.log(name) } } var person = new Person('hello', 18)
構造函數模式隱試的在最後返回return this
因此在缺乏new
的狀況下,會將屬性和方法添加給全局對象,瀏覽器端就會添加給window
對象,能夠根據return this
的特性調用call
或者apply
指定this
原型模式
function Person() {} Person.prototype.name = 'hanmeimei'; Person.prototype.say = function() { alert(this.name); } Person.prototype.friends = ['lilei']; var person = new Person();
實現了方法與屬性的共享,能夠動態添加對象的屬性和方法。可是沒有辦法建立實例本身的屬性和方法,也沒有辦法傳遞參數
構造函數和原型組合
function Person(name, age) { this.name = name this.age = age } Person.prototype.say = function() { console.log(this.name) } var person = new Person('hello')
還有好幾種模式,感興趣的小夥伴能夠參考 紅寶書,大家確定知道的了!
淺拷貝
Array.prototype.slice()
也能夠完成對一個數組或者對象的淺拷貝Object.assign()
方法深拷貝
JSON.parse(JSON.stringify(目標對象)
,缺點就是隻能拷貝符合JSON
數據標準類型的對象更多參考 JavaScript 中的淺拷貝與深拷貝
簡單來講,閉包就是可以讀取其餘函數內部變量的函數
function Person() { var name = 'hello' function say () { console.log(name) } return say() } Person() // hello
因爲 JavaScript 特殊的做用域,函數外部沒法直接讀取內部的變量,內部能夠直接讀取外部的變量,從而就產生了閉包的概念
用途:
最大用處有兩個,一個是前面提到的能夠讀取函數內部的變量,另外一個就是讓這些變量的值始終保持在內存中
注意點:
因爲閉包會使得函數中的變量都被保存在內存中,內存消耗很大,因此不能濫用閉包,不然會形成網頁的性能問題,在IE中可能致使內存泄露
更多參考 JavaScript 中的閉包
首先明確一點,JavaScript是基於原型的
每一個構造函數(constructor)都有一個原型對象(prototype),原型對象都包含一個指向構造函數的指針,而實例(instance)都包含一個指向原型對象的內部指針.
圖解:
prototype
屬性,這個屬性指向一個對象,也就是原型對象constructor
屬性,指向指向它的那個構造函數[[prototype]]
,指向它的原型對象那麼什麼是原型鏈:
JavaScript
中全部的對象都是由它的原型對象繼承而來。而原型對象自身也是一個對象,它也有本身的原型對象,這樣層層上溯,就造成了一個相似鏈表的結構,這就是原型鏈
全部原型鏈的終點都是
Object
函數的prototype
屬性。Objec.prototype
指向的原型對象一樣擁有原型,不過它的原型是null
,而null
則沒有原型
更多參考 JavaScript 中的原型與原型鏈
function Animal() {} Animal.prototype.name = 'cat' Animal.prototype.age = 1 Animal.prototype.say = function() {console.log('hello')} var cat = new Animal() cat.name // cat cat.age // 1 cat.say() // hello
最簡單的繼承實現方式,可是也有其缺點
new
語句以後執行,不能放到構造器中function Animal() { this.species = "動物" } function Cat(name, age) { Animal.call(this) this.name = name this.age = age } var cat = new Cat('豆豆', 2) cat.name // 豆豆 cat.age // 2 cat.species // 動物
使用call或apply方法,將父對象的構造函數綁定在子對象上.
function Animal() { this.species = "動物" } function Cat(name){ Animal.call(this) this.name = name } Cat.prototype = new Animal() // 重寫原型 Cat.prototype.constructor = Cat
若是沒有
Cat.prototype = new Animal()
這一行,Cat.prototype.constructor
是指向Cat
的;加了這一行之後,Cat.prototype.constructor
指向Animal
.這顯然會致使繼承鏈的紊亂(cat1明明是用構造函數Cat生成的),所以咱們必須手動糾正,將Cat.prototype
對象的constructor
值改成Cat
extends
繼承 ES6新增繼承方式,Class 能夠經過extends關鍵字實現繼承class Animal { } class Cat extends Animal { constructor() { super(); } }
使用
extends
實現繼承,必須添加super
關鍵字定義子類的constructor
,這裏的super()
就至關於Animal.prototype.constructor.call(this)
固然,還有不少種實現繼承的方式,這裏就很少說了。而後,再推薦一波 紅寶書
更多參考 JavaScript 中的繼承
同步模式
同步模式,又稱阻塞模式。javascript
在默認狀況下是會阻塞加載的。當前面的 javascript
請求沒有處理和執行完時,會阻止瀏覽器的後續處理
異步模式
異步加載又叫非阻塞,瀏覽器在下載執行 js
同時,還會繼續進行後續頁面的處理
異步加載 JavaScript
script
標籤defer
async
defer
屬性和async
都是屬於script
標籤上面的屬性,二者都能實現JavaScript
的異步加載。不一樣之處在於:async
在異步加載完成的時候就立刻開始執行了,defer
會等到html
加載完畢以後再執行
因爲瀏覽器的 同源策略,在出現 域名、端口、協議有一種不一致時,就會出現跨域,屬於瀏覽器的一種安全限制。
解決跨域問題有不少種方式,經常使用的就是如下幾種:
jsonp
跨域:動態建立script
,再請求一個帶參網址實現跨域通訊.缺點就是隻能實現 get
一種請求document.domain + iframe
跨域:兩個頁面都經過js強制設置document.domain
爲基礎主域,就實現了同域.可是僅限主域相同,子域不一樣的跨域應用場景Access-Control-Allow-Origin
便可,前端無須設置,若要帶cookie
請求:先後端都須要設置nginx
反向代理接口跨域:同源策略是瀏覽器的安全策略,不是HTTP
協議的一部分。服務器端調用HTTP
接口只是使用HTTP
協議,不會執行JS腳本,不須要同源策略,也就不存在跨越問題WebSocket
協議跨域在 JavaScript
中,研究 this
通常都是 this
的指向問題,核心就是 this
永遠指向最終調用它的那個對象,除非改變 this
指向或者箭頭函數那種特殊狀況
function test() { console.log(this); } test() // window var obj = { foo: function () { console.log(this.bar) }, bar: 1 }; var foo = obj.foo; var bar = 2; obj.foo() // 1 foo() // 2 // 函數調用的環境不一樣,所獲得的結果也是不同的
相同點:三者均可以改變 this 的指向
不一樣點:
var obj = { name : 'sss' } function func(firstName, lastName){ console.log(firstName + ' ' + this.name + ' ' + lastName); } func.apply(obj, ['A', 'B']); // A sss B
call
方法第一個參數也是做爲函數上下文的對象,可是後面傳入的是一個參數列表,而不是單個數組var obj = { name: 'sss' } function func(firstName, lastName) { console.log(firstName + ' ' + this.name + ' ' + lastName); } func.call(obj, 'C', 'D'); // C sss D
bind
接受的參數有兩部分,第一個參數是是做爲函數上下文的對象,第二部分參數是個列表,能夠接受多個參數var obj = { name: 'sss' } function func() { console.log(this.name); } var func1 = func.bind(null, 'xixi'); func1();
apply
、call
方法都會使函數當即執行,所以它們也能夠用來調用函數
bind
方法不會當即執行,而是返回一個改變了上下文this
後的函數。而原函數func
中的this
並無被改變,依舊指向全局對象window
bind
在傳遞參數的時候會將本身帶過去的參數排在原函數參數以前
function func(a, b, c) { console.log(a, b, c); } var func1 = func.bind(this, 'xixi'); func1(1,2) // xixi 1 2
內存泄漏:是指一塊被分配的內存既不能使用,又不能回收,直到瀏覽器進程結束
可能形成內存泄漏的操做:
你可能還須要知道 垃圾回收機制 此外,高程上面對垃圾回收機制的介紹也很全面,有興趣的小夥伴能夠看看
事件代理:通俗來講就是將元素的事件委託給它的父級或者更外級元素處理
原理:利用事件冒泡機制實現的
優勢:只須要將同類元素的事件委託給父級或者更外級的元素,不須要給全部元素都綁定事件,減小內存空間佔用,提高性能; 動態新增的元素無需從新綁定事件
AMD
和CMD
都是爲了解決瀏覽器端模塊化問題而產生的,AMD
規範對應的庫函數有Require.js
,CMD
規範是在國內發展起來的,對應的庫函數有Sea.js
AMD和CMD最大的區別是對依賴模塊的執行時機處理不一樣
一、AMD推崇依賴前置,在定義模塊的時候就要聲明其依賴的模塊
二、CMD推崇就近依賴,只有在用到某個模塊的時候再去require
ECMAScript 6.0 是 JavaScript 語言的下一代標準
新增的特性:
let
const
includes()
startsWith()
endsWith()
等Array.from()
Array.of()
entries()
keys()
values()
等Object.is()
Object.assign()
entries()
keys()
values()
等rest
參數、函數參數默認值等Set
和 Map
Proxy
Promise
對象async
函數 await
命令Class
類Module
體系 模塊的加載和輸出方式瞭解更多,參考 ES6入門-阮一峯
ES6 容許使用「箭頭」(=>)定義函數
var f = v => v; // 等同於 var f = function (v) { return v; }
注意點:
this
對象,就是定義時所在的對象,而不是使用時所在的對象new
命令,不然會拋出一個錯誤arguments
對象,該對象在函數體內不存在。若是要用,能夠用 rest
參數代替Promise 是異步編程的一種解決方案,比傳統的解決方案——回調函數和事件——更合理和更強大.所謂Promise,簡單說就是一個容器,裏面保存着某個將來纔會結束的事件(一般是一個異步操做)的結果 --ES6入門-阮一峯
Promise
對象表明一個異步操做,有三種狀態:pending
(進行中)、fulfilled
(已成功)和rejected
(已失敗)。只有異步操做的結果,能夠決定當前是哪種狀態,任何其餘操做都沒法改變這個狀態
特色:
Promise
新建後就會當即執行const promise = new Promise(function(resolve, reject) { // ... some code if (/* 異步操做成功 */){ resolve(value); } else { reject(error); } })
Promise實例生成之後,能夠用then方法分別指定resolved狀態和rejected狀態的回調函數
promise.then(function(value) { // success }, function(error) { // failure })
then
方法返回的是一個新的Promise實例
Promise.prototype.catch
用於指定發生錯誤時的回調函數,具備「冒泡」性質,會一直向後傳遞,直到被捕獲爲止。也就是說,錯誤老是會被下一個catch
語句捕獲
getJSON('/post/1.json').then(function(post) { return getJSON(post.commentURL); }).then(function(comments) { // some code }).catch(function(error) { // 處理前面三個Promise產生的錯誤 });
catch
方法返回的仍是一個Promise
對象,所以後面還能夠接着調用then
方法
出去上述方法,Promise還有其餘用法,小夥伴們能夠在這裏查看大佬寫的文章 ES6入門-阮一峯
async
函數是什麼?一句話,它就是Generator
函數的語法糖
瞭解Generator函數的小夥伴,這裏 傳送門
async
特色:
async
函數返回一個Promise
對象,可使用then
方法添加回調函數。當函數執行的時候,一旦遇到await
就會先返回,等到異步操做完成,再接着執行函數體內後面的語句
async
函數內部return
語句返回的值,會成爲then
方法回調函數的參數
async
函數返回的Promise
對象,必須等到內部全部await
命令後面的Promise
對象執行完,纔會發生狀態改變,除非遇到return
語句或者拋出錯誤
async
函數內部拋出錯誤,會致使返回的Promise
對象變爲reject
狀態。拋出的錯誤對象會被catch
方法回調函數接收到
function timeout(ms) { return new Promise((resolve) => { setTimeout(resolve, ms); }); } async function asyncPrint(value, ms) { await timeout(ms); console.log(value); } asyncPrint('hello world', 50);
await
命令:await
命令後面是一個Promise
對象,返回該對象的結果。若是不是Promise
對象,就直接返回對應的值
async function f() { // 等同於 // return 123; return await 123; } f().then(v => console.log(v)) // 123
await
命令後面是一個thenable
對象(即定義then方法的對象),那麼await
會將其等同於Promise
對象.也就是說就算一個對象不是Promise
對象,可是隻要它有then
這個方法,await
也會將它等同於Promise
對象
使用注意點:
await
命令後面的 Promise
對象,運行結果多是 rejected
,因此最好把 await
命令放在 try...catch
代碼塊中await
命令後面的異步操做,若是不存在繼發關係,最好讓它們同時觸發await
命令只能用在 async
函數之中,若是用在普通函數,就會報錯瞭解更多,請點擊 這裏
export
與export default
都可用於導出常量、函數、文件、模塊等
在一個文件或模塊中,
export
、import
能夠有多個,export default
僅有一個
經過
export
方式導出,在導入時要加{ }
,export default
則不須要
使用
export default
命令,爲模塊指定默認輸出,這樣就不須要知道所要加載模塊的變量名;export
加載的時候須要知道加載模塊的變量名
export default
命令的本質是將後面的值,賦給default
變量,因此能夠直接將一個值寫在export default
以後
參見 雅虎14條前端性能優化
首選明確兩點:
JavaScript
是單線程語言
JavaScript
的Event Loop
是JS
的執行機制, 也就是事件循環
console.log(1) setTimeout(function(){ console.log(2) },0) console.log(3) // 1 3 2
JavaScript
將任務分爲同步任務和異步任務,執行機制就是先執行同步任務,將同步任務加入到主線程,遇到異步任務就先加入到event table
,當全部的同步任務執行完畢,若是有可執行的異步任務,再將其加入到主線程中執行
視頻詳解,移步 這裏
setTimeout(function(){console.log(1);},0); new Promise(function(resolve){ console.log(2); for(var i = 0; i < 10000; i++){ i == 99 && resolve(); } }).then(function(){ console.log(3) }); console.log(4); // 2 4 3 1
在異步任務中,定時器也屬於特殊的存在。有人將其稱之爲 宏任務、微任務,定時器就屬於宏任務的範疇。