摘要:隱式綁定即綁定到最頂層或最近調(diào)用對(duì)象上顯式綁定即用或手動(dòng)進(jìn)行綁定方法實(shí)現(xiàn)綁定構(gòu)造函數(shù)不存在其實(shí)在中不存在構(gòu)造函數(shù),我們所說(shuō)的構(gòu)造函數(shù)其實(shí)就是普通的函數(shù),它只是用被構(gòu)造調(diào)用而已。
JS是編譯型語(yǔ)言
編譯發(fā)生在代碼執(zhí)行前幾微秒,簡(jiǎn)單來(lái)說(shuō)就是js在執(zhí)行前要進(jìn)行編譯,編譯過(guò)程發(fā)生在代碼執(zhí)行前幾微妙,甚至更短。
編譯的步驟詞法分析
以var a = 2 為例,詞法分析會(huì)將其分成三個(gè)有意義的代碼塊即詞法單元。
語(yǔ)法分析
將詞法單元組合生成代表了程序語(yǔ)法的結(jié)構(gòu)的樹(shù),即抽象語(yǔ)法書(shū)(AST)。
代碼生成
將AST生成可執(zhí)行的代碼。即將AST轉(zhuǎn)化成一組機(jī)器指令。???
如果查找的目的是對(duì)變量進(jìn)行賦值,那么就會(huì)使用 LHS 查詢;如果目的是獲取變量的值,就會(huì)使用 RHS 查詢。
詞法作用域決定于你在寫(xiě)代碼時(shí)的塊級(jí)作用域
優(yōu)化依賴于詞法的靜態(tài)分析
eval with 會(huì)創(chuàng)建新的作用域在詞法分析階段,無(wú)法知道eval with會(huì)對(duì)作用域做怎樣的修改,此時(shí)引擎不再對(duì)作用域進(jìn)行任何優(yōu)化
函數(shù)作用域 函數(shù)聲明 函數(shù)表達(dá)式區(qū)分函數(shù)聲明和表達(dá)式最簡(jiǎn)單的方法是看 function 關(guān)鍵字出現(xiàn)在聲明中的位
置(不僅僅是一行代碼,而是整個(gè)聲明中的位置)。如果 function 是聲明中
的第一個(gè)詞,那么就是一個(gè)函數(shù)聲明,否則就是一個(gè)函數(shù)表達(dá)式。
隱式的生成塊級(jí)作用域
不存在變量提升
提升 原因變量(包括函數(shù)在內(nèi))的所有聲明都會(huì)優(yōu)先執(zhí)行,只有聲明本身會(huì)提升,而賦值或其他運(yùn)行邏輯會(huì)留在原位置
過(guò)程這意味著無(wú)論作用域中的聲明出現(xiàn)在什么地方,都將在代碼本身被執(zhí)行前首先進(jìn)行處理。
可以將這個(gè)過(guò)程形象地想象成所有的聲明(變量和函數(shù))都會(huì)被“移動(dòng)”到各自作用域的
最頂端,這個(gè)過(guò)程被稱為提升。
聲明本身會(huì)被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會(huì)提升。
當(dāng)函數(shù)能夠記住或訪問(wèn)所在的詞法作用域,及時(shí)是被作用域外調(diào)用,就產(chǎn)生了閉包
模塊現(xiàn)代模塊機(jī)制
未來(lái)的模塊機(jī)制
關(guān)于this 綁定時(shí)間點(diǎn)是在函數(shù)運(yùn)行時(shí)綁定的,而非定義時(shí)。它的上下文取決于函數(shù)調(diào)用時(shí)的各種條件,和在哪里定義的沒(méi)有關(guān)系,只取決于函數(shù)的調(diào)用方式。
綁定過(guò)程當(dāng)函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)執(zhí)行上下文,在這個(gè)上下文里包含了函數(shù)在哪里沒(méi)調(diào)用(調(diào)用棧),調(diào)用函數(shù)的方法,參數(shù)等。this作為執(zhí)行上下文的一個(gè)屬性,可以在函數(shù)執(zhí)行的過(guò)程中用到。
綁定類型
默認(rèn)綁定
即綁定到全局,嚴(yán)格模式下回綁定到undefined。
function foo() { console.log( this.a ); } var a = 2; (function(){ "use strict"; foo(); // 2 })()
隱式綁定
即綁定到最頂層(或最近調(diào)用對(duì)象)上
function fun() { console.log(this.a) } var obj2 = { a: 3, fun: fun, } var obj1 = { a: 2, obj2: obj2, } obj1.obj2.fun() // 3
顯式綁定
即用call或apply手動(dòng)進(jìn)行綁定
bind方法實(shí)現(xiàn)
new綁定(構(gòu)造函數(shù))
不存在
其實(shí)在js中不存在構(gòu)造函數(shù),我們所說(shuō)的構(gòu)造函數(shù)其實(shí)就是普通的函數(shù),它只是用new被“構(gòu)造調(diào)用”而已。
new發(fā)生了什么?
創(chuàng)建(或者說(shuō)構(gòu)造)一個(gè)全新的對(duì)象。
這個(gè)新對(duì)象會(huì)被執(zhí)行[[原型]]連接。
這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this。
如果函數(shù)沒(méi)有返回其他對(duì)象,那么new表達(dá)式中的函數(shù)調(diào)用會(huì)自動(dòng)返回這個(gè)新對(duì)象。
箭頭函數(shù) =>
對(duì)象 內(nèi)置對(duì)象基本類型在需要的時(shí)候(比如說(shuō)獲取長(zhǎng)度),會(huì)被引擎默認(rèn)轉(zhuǎn)成內(nèi)置對(duì)象,從而進(jìn)行方法的調(diào)用。
基礎(chǔ)類型并不是繼承自內(nèi)置對(duì)象?
var strPrimitive = "I am a string"; typeof strPrimitive; // "string" strPrimitive instanceof String; // false var strObject = new String( "I am a string" ); typeof strObject; // "object" strObject instanceof String; // true Object.prototype.toString.call( strObject ); // [object String]null
typeof null === Object;
原理是這樣的,不同的對(duì)象在底層都表示為二進(jìn)制,在 JavaScript 中二進(jìn)制前三位都為 0 的話會(huì)被判
斷為 object 類型,null 的二進(jìn)制表示是全 0,自然前三位也是 0,所以執(zhí)行 typeof 時(shí)會(huì)返回“object”
淺拷貝
Object.assign({}, obj)
深拷貝
JSON.stringify
getOwnPropertyDescriptor(myObj, "a") defineProperty Object.defineProperty(myObj, "a", { value: 2, ?writable: true, configurable: true, enumerable: true ?})Getter 、Setter
var obj = { get a() { return this._a_ }, set a(val) { this._a_ = val * 5 } } obj.a = 10 console.log(obj.a) // 50 ? var obj2 = {} Object.defineProperty(obj2, "a", { get: function() { return this._a_ }, set: function(val) { this._a_ = val * 2 } }) obj2.a = 15 console.log(obj2.a) // 30存在性
in
"a" in obj1 會(huì)檢查obj及其原型鏈上是否有"a"
hasOwnProperty
不會(huì)檢查原型鏈,如果需要可以O(shè)bject.prototype.hasOwnProperty.call(myObj, "a")
返回實(shí)例對(duì)象O的構(gòu)造函數(shù)(的引用)。任何一個(gè)prototype對(duì)象都有一個(gè)constructor屬性,指向它的構(gòu)造函數(shù),每一個(gè)實(shí)例也有一個(gè)constructor屬性,默認(rèn)調(diào)用prototype對(duì)象的constructor屬性?
例如
function Test() { this.name = "test" } var test = new Test() console.log(test.constructor === Test) // true類constructor
構(gòu)造函數(shù) constructor 是用于創(chuàng)建和初始化類中創(chuàng)建的一個(gè)對(duì)象的一種特殊方法.
class Polygon { constructor() { this.name = "Polygon"; } } class Square extends Polygon { constructor() { super(); } } class Rectangle {} Object.setPrototypeOf(Square.prototype, Rectangle.prototype); console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); //false console.log(Object.getPrototypeOf(Square.prototype) === Rectangle.prototype); //true let newInstance = new Square(); console.log(newInstance.name); //Polygon?proto
實(shí)例對(duì)象__proto__指向生成改對(duì)象的構(gòu)造函數(shù)的原型
例如
|function Test() { this.name = "test" } Test.prototype = { color: "red" } var test = new Test() console.log(test.__proto__ === Test.prototype) // true console.log(test.__proto__)Object.create
var foo = { something: function() { console.log( "Tell me something good..." ); } }; var bar = Object.create( foo ); bar.something(); // Tell me something good... Object.create(..) 會(huì)創(chuàng)建一個(gè)新對(duì)象(bar)并把它關(guān)聯(lián)到我們指定的對(duì)象(foo)
這樣 我們就可以充分發(fā)揮 [[Prototype]]
機(jī)制的威力(委托)并且避免不必要的麻煩
(比如使 用 new 的構(gòu)造函數(shù)調(diào)用會(huì)生成 .prototype 和 .constructor 引用)。
?
缺點(diǎn)
實(shí)例的屬性都會(huì)指向同一個(gè)引用
實(shí)現(xiàn)
function Parent() { this.names = [1, 2, 3] } function Child() { } Child.prototype = new Parent() var child1 = new Child() var child2 = new Child() child1.names.push(4) console.log(child1.names) // [1,2, 3,4] console.log(child2.names) // [1,2, 3,4]借用構(gòu)造函數(shù)
實(shí)現(xiàn)
function Parent() { this.names = [1, 2, 3] this.getName = function () { console.log(this.name) } } function Child() { Parent.call(this) } var child1 = new Child() var child2 = new Child() child1.names.push(4) console.log(child1.names) console.log(child2.names)
缺點(diǎn)
每個(gè)子實(shí)例都會(huì)實(shí)例化方法一次,內(nèi)存爆炸
實(shí)現(xiàn)
function Parent() { this.names = [1, 2, 3] } Parent.prototype.getName = function () { console.log(this.names) } function Child() { Parent.call(this) } Child.prototype = new Parent() var child1 = new Child() var child2 = new Child() child1.names.push(4) child1.getName() child2.getName()
缺點(diǎn)
子類實(shí)例上有一份父類的屬性,二者重復(fù)造成內(nèi)存浪費(fèi)
父類的構(gòu)造函數(shù)被調(diào)用了兩次?
寄生式組合繼承實(shí)現(xiàn)
function Parent() { this.names = [1, 2, 3] } Parent.prototype.getName = function () { console.log(this.names) } function Child() { Parent.call(this) } Child.prototype = Object.create(Parent.prototype) var child1 = new Child() var child2 = new Child() child1.names.push(4) child1.getName() child2.getName()
優(yōu)點(diǎn)
屬性不會(huì)再原型鏈上重復(fù)
js中的繼承其實(shí)就是在對(duì)象間建立關(guān)聯(lián)關(guān)系,而行為委托就是建立這種關(guān)聯(lián)關(guān)系的紐帶。
("原型")面向?qū)ο箫L(fēng)格function Foo(who) { this.me = who; } Foo.prototype.identify = function () { return "I am" + this.me; }; function Bar(who) { Foo.call(this,who); } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.speak = function () { alert("Hello," + this.identify() + "."); }; var b1 = new Bar("b1"); var b2 = new Bar("b2"); b1.speak(); b2.speak();對(duì)象關(guān)聯(lián)風(fēng)格
Foo = { init:function (who) { this.me = who; }, identify:function () { return "I am" + this.name } }; Bar = Object.create(Foo); Bar.speak = function () { alert("hello," + this.identify() + "."); }; var b3 = Object.create(Bar); b3.init("b3"); var b4 = Object.create(Bar); b4.init("b4"); b1.speak(); b2.speak();
?
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/97508.html
摘要:注此讀書(shū)筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過(guò)閱讀你不知道的后的理解。作用域及閉包基礎(chǔ),代碼運(yùn)行的幕后工作者引擎及編譯器。 注:此讀書(shū)筆記只記錄本人原先不太理解的內(nèi)容經(jīng)過(guò)閱讀《你不知道的JS》后的理解。 作用域及閉包基礎(chǔ),JS代碼運(yùn)行的幕后工作者:引擎及編譯器。引擎負(fù)責(zé)JS程序的編譯及執(zhí)行,編譯器負(fù)責(zé)詞法分析和代碼生成。那么作用域就像一個(gè)容器,引擎及編譯器都從這里提取東西。 ...
摘要:異步請(qǐng)求線程在在連接后是通過(guò)瀏覽器新開(kāi)一個(gè)線程請(qǐng)求將檢測(cè)到狀態(tài)變更時(shí),如果設(shè)置有回調(diào)函數(shù),異步線程就產(chǎn)生狀態(tài)變更事件,將這個(gè)回調(diào)再放入事件循環(huán)隊(duì)列中。 基礎(chǔ):瀏覽器 -- 多進(jìn)程,每個(gè)tab頁(yè)獨(dú)立一個(gè)瀏覽器渲染進(jìn)程(瀏覽器內(nèi)核) 每個(gè)瀏覽器渲染進(jìn)程是多線程的,主要包括:GUI渲染線程 JS引擎線程 也稱為JS內(nèi)核,負(fù)責(zé)處理Javascript腳本程序。(例如V8引擎) JS引擎線程負(fù)...
摘要:如果存在于原型鏈上層,賦值語(yǔ)句的行為就會(huì)有些不同。中包含的屬性會(huì)屏蔽原型鏈上層的所有屬性,因?yàn)榭偸菚?huì)選擇原型鏈中最底層的屬性。如果不直接存在于中而是存在于原型鏈上層時(shí)會(huì)出現(xiàn)的三種情況。類構(gòu)造函數(shù)原型函數(shù),兩個(gè)函數(shù)通過(guò)屬性和屬性相關(guān)聯(lián)。 1 [[Prototype]] 對(duì)于默認(rèn)的 [[Get]] 操作來(lái)說(shuō),如果無(wú)法在對(duì)象本身找到需要的屬性,就會(huì)繼續(xù)訪問(wèn)對(duì)象的 [[Prototype]] ...
摘要:如果存在于原型鏈上層,賦值語(yǔ)句的行為就會(huì)有些不同。中包含的屬性會(huì)屏蔽原型鏈上層的所有屬性,因?yàn)榭偸菚?huì)選擇原型鏈中最底層的屬性。如果不直接存在于中而是存在于原型鏈上層時(shí)會(huì)出現(xiàn)的三種情況。類構(gòu)造函數(shù)原型函數(shù),兩個(gè)函數(shù)通過(guò)屬性和屬性相關(guān)聯(lián)。 1 [[Prototype]] 對(duì)于默認(rèn)的 [[Get]] 操作來(lái)說(shuō),如果無(wú)法在對(duì)象本身找到需要的屬性,就會(huì)繼續(xù)訪問(wèn)對(duì)象的 [[Prototype]] ...
摘要:閉包在循環(huán)中的應(yīng)用延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行事實(shí)上,當(dāng)定時(shí)器運(yùn)行時(shí)即使沒(méi)給迭代中執(zhí)行的是多有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才會(huì)被執(zhí)行,因此會(huì)每次輸出一個(gè)出來(lái)。 閉包在循環(huán)中的應(yīng)用 延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束時(shí)才執(zhí)行;事實(shí)上,當(dāng)定時(shí)器運(yùn)行時(shí)即使沒(méi)給迭代中執(zhí)行的是 setTime(..., 0),多有的回調(diào)函數(shù)依然是在循環(huán)結(jié)束后才會(huì)被執(zhí)行,因此會(huì)每次輸出一個(gè)6出來(lái)。 for(var...
showImg(https://segmentfault.com/img/bVbtd6M?w=1181&h=1365); showImg(https://segmentfault.com/img/bVbtd6T?w=1243&h=1984);
閱讀 3880·2021-09-23 11:51
閱讀 3067·2021-09-22 15:59
閱讀 868·2021-09-09 11:37
閱讀 2070·2021-09-08 09:45
閱讀 1267·2019-08-30 15:54
閱讀 2065·2019-08-30 15:53
閱讀 492·2019-08-29 12:12
閱讀 3290·2019-08-29 11:15