摘要:詞法熟悉語法的開發(fā)者,箭頭函數(shù)在涉及綁定時(shí)的行為和普通函數(shù)的行為完全不一致。被忽略的作為的綁定對(duì)象傳入,使用的是默認(rèn)綁定規(guī)則。使用內(nèi)置遍歷數(shù)組返回迭代器函數(shù)普通對(duì)象不含有,無法使用,可以進(jìn)行改造,個(gè)人博客地址
this詞法
熟悉ES6語法的開發(fā)者,箭頭函數(shù)在涉及this綁定時(shí)的行為和普通函數(shù)的行為完全不一致。跟普通this綁定規(guī)則不一樣,它使用了當(dāng)前的詞法作用域覆蓋了this本來的值。
誤解this理解成指向函數(shù)本身,函數(shù)對(duì)象的屬性(Fun.X)不是this.X 【X】
this指向函數(shù)的作用域 【X】
this是運(yùn)行時(shí)進(jìn)行綁定的,而不是編寫時(shí)綁定的,它的執(zhí)行上下文取決于函數(shù)調(diào)用時(shí)的各種條件,this的綁定和函數(shù)聲明的位置沒有任何關(guān)系,只取決于函數(shù)的調(diào)用方式(調(diào)用位置),具有動(dòng)態(tài)性,簡單地說,函數(shù)執(zhí)行過程中的調(diào)用位置決定了this的綁定對(duì)象。
函數(shù)被調(diào)用時(shí),會(huì)創(chuàng)建一個(gè)活動(dòng)記錄,這個(gè)也稱作執(zhí)行上下文,這個(gè)記錄包含了函數(shù)在哪里被調(diào)用(調(diào)用棧)、函數(shù)調(diào)用方式、傳入的參數(shù)等信息,而this就是執(zhí)行上下文的一個(gè)屬性,函數(shù)調(diào)用時(shí)會(huì)被用到。
this綁定規(guī)則默認(rèn)綁定,this指向全局對(duì)象(嚴(yán)格模式,不允許使用)
隱式綁定,會(huì)把函數(shù)調(diào)用的this綁定到所在的上下文對(duì)象,對(duì)于隱式綁定,常常伴隨著隱式丟失的問題,函數(shù)別名、傳入回調(diào)函數(shù)、函數(shù)傳入內(nèi)置函數(shù)均會(huì)造成此問題
顯式綁定,就是常見call、apply方法,仍無法解決綁定丟失問題,但有個(gè)變種方法,叫做硬綁定
└── 硬綁定,函數(shù)bar中強(qiáng)制綁定(顯示綁定)綁定foo在obj中執(zhí)行
├── 包裹函數(shù) ├── 輔助函數(shù)(bind基本實(shí)現(xiàn)原理,下面有詳細(xì)實(shí)現(xiàn))
new綁定,過程如下(發(fā)生在構(gòu)造函數(shù)調(diào)用時(shí)):
1、創(chuàng)建(或者說構(gòu)造)一個(gè)新對(duì)象
2、這個(gè)新對(duì)象會(huì)被執(zhí)行[[Porototype]]連接
3、這個(gè)新對(duì)象會(huì)被綁定到函數(shù)調(diào)用的this
4、如果函數(shù)沒有返回其他的對(duì)象,那么new表達(dá)式的函數(shù)調(diào)用會(huì)自動(dòng)返回新對(duì)象
規(guī)則優(yōu)先級(jí):默認(rèn)綁定 < 隱式綁定 < 顯式綁定 < new綁定
☆☆☆☆☆☆ 輔助函數(shù)與bind函數(shù)的實(shí)現(xiàn) ☆☆☆☆☆☆
function bind(fn, obj) { return function() { fn.apply(obj, arguments); } }
摘自MDN:
if (!Function.prototype.bind) { Function.prototype.bind = function(oThis) { if (typeof this !== "function") { throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); } var aArgs = Array.prototype.slice.call(arguments, 1), fToBind = this, fNOP = function() {}, fBound = function() { // this instanceof fBound === true時(shí),說明返回的fBound被當(dāng)做new的構(gòu)造函數(shù)調(diào)用 // 關(guān)鍵代碼,如果是new調(diào)用,就是使用新創(chuàng)建的this替換硬綁定的this,說明了new綁定優(yōu)先級(jí)大于硬綁定 return fToBind.apply(this instanceof fBound ? this : oThis, // 獲取調(diào)用時(shí)(fBound)的傳參.bind 返回的函數(shù)入?yún)⑼沁@么傳遞的 aArgs.concat(Array.prototype.slice.call(arguments))); }; // 維護(hù)原型關(guān)系 if (this.prototype) { fNOP.prototype = this.prototype; } // 下行的代碼使fBound.prototype是fNOP的實(shí)例,因此 // 返回的fBound若作為new的構(gòu)造函數(shù),new生成的新對(duì)象作為this傳入fBound,新對(duì)象的__proto__就是fNOP的實(shí)例 fBound.prototype = new fNOP(); return fBound; }; }更安全的this
bind輔助函數(shù)修改改變this的同時(shí),可以使用Object.create(null),如.call/.apply(Object.create(null), ...argument),這樣可以有效防止修改全局對(duì)象。
被忽略的thisnull/undefined作為this的綁定對(duì)象傳入call、apply,使用的是默認(rèn)綁定規(guī)則。
軟綁定上述對(duì)硬綁定的介紹,會(huì)強(qiáng)制把this強(qiáng)制綁定到指定的對(duì)象上,防止了函數(shù)調(diào)用應(yīng)用默認(rèn)綁定規(guī)則,但是造成的問題就是,不夠靈活,使用不了隱式綁定和顯式綁定來修改this,于此同時(shí),軟綁定便出現(xiàn)了。
if (!Function.prototype.softBind) { Function.prototype.softBind = function(obj) { var fn = this; // 捕獲所有curried參數(shù) var curried = [].slice.call(arguments, 1); var bound = function() { return fn.apply( (!this || this === (window || global)) ? obj : this, curried.concat.apply(curried, arguments) ); } bound.prototype = Object.create(fn.prototype); return bound; } }
軟綁定DEMO:
function foo() { console.log("name:" + this.name); } var obj = { name: "obj" }; var obj2 = { name: "obj2" }; var obj3 = { name: "obj3" }; var fooBj = foo.softBind(obj); fooBj(); // name: obj obj2.foo = foo.softBind(obj2); obj2.foo(); // name: obj2 fooBj.call(obj3); // name: obj3 setTimeout(obj2.foo, 10); // name: obj基本類型、內(nèi)置對(duì)象
基本類型:string、number、boolean、null、undefined、object
內(nèi)置對(duì)象(也是內(nèi)置函數(shù)): String、Number、Boolean、Object、Function、Array、Date、RegExp、Error
日常開發(fā),大家可能會(huì)有疑問,比如var a = "i am string"中a變量,它可以使用a.length、a.charAt(0)等屬性和方法。它本來是一個(gè)字符串,為什么會(huì)有類似對(duì)象的特性呢,這里會(huì)涉及到一個(gè)基本包裝對(duì)象,可以怎么理解這樣的一個(gè)概念性知識(shí),一瞬間的引用類型,用完即毀,真正的引用類型會(huì)一直存在內(nèi)存中,而基本包裝對(duì)象只會(huì)存在一瞬間。
衍生方法:typeof、instanceof、Object.prototype.toString.call
對(duì)象對(duì)象的內(nèi)容是由一些存儲(chǔ)在特定命名位置的值組成的,叫做屬性(指針),有兩種訪問方式,myObject["a"]、myObject.a,對(duì)象屬性同時(shí)也是無序的。
ES6可計(jì)算屬性名:
const prefix = "a"; const myObject = { [prefix + "bar"]: "xxxx" }
記住,函數(shù)永遠(yuǎn)不屬于一個(gè)對(duì)象,只是一個(gè)引用,只是函數(shù)的this,會(huì)因?yàn)殡[性綁定,在上下文做一層綁定而已。
復(fù)制對(duì)象、屬性描述符深復(fù)制,JSON.parse(JSON.stringify(obj))
淺復(fù)制,Object.assign(...),會(huì)遍歷一個(gè)或多個(gè)源對(duì)象的所有可枚舉的自由鍵到目標(biāo)對(duì)象,源對(duì)象的一些特性(如writable)不會(huì)被復(fù)制
屬性描述符,即writable、configuable、enumerable、value
獲得屬性描述符,Object.getOwnPropertyDescriptor(myObject, "a")
設(shè)置屬性描述符,Object.defineProperty(myObject, "a", {...})
configuable配置為false,不能使用delete關(guān)鍵字
enumerable控制屬性是否可枚舉
訪問描述符,(Getter/Setter),可以改寫默認(rèn)的value,
var myObject = { get a() { return 2; } } myObject.a // 2 Object.defineProperty(myObject, "b", { get: function() { return this.a * 2 // 指向當(dāng)前對(duì)象 } }); myObject.b // 4遍歷對(duì)象屬性的幾種方法
對(duì)象不可變性for...in,遍歷對(duì)象自身及原型上可枚舉的屬性
Object.keys(),遍歷對(duì)象自身可枚舉的屬性
Object.getOwnPropertyNames,遍歷對(duì)象自身的屬性
Object.getOwnPropertySymbol,遍歷對(duì)象自身Symbol類型屬性
Reflect.ownkeys,遍歷對(duì)象自身的屬性(包含不可枚舉屬性,Symbol類型屬性)
如果你希望對(duì)象屬性或是對(duì)象是不可改變,可以通過配置對(duì)象的屬性描述符來實(shí)現(xiàn),但是這種不可變是一種淺不可變,如果對(duì)象中屬性的引用是對(duì)象、數(shù)組、函數(shù),那么它們是可變的,實(shí)現(xiàn)方式有如下:
存在性對(duì)象常量,writable:false | configuable:false
禁止擴(kuò)展,Object.preventExtensions(obj)
密封,Object.seal(obj)調(diào)用禁止擴(kuò)展,且不能重新配置,及刪除屬性,及configuable:false
凍結(jié),Object.freeze(obj),在密封的基礎(chǔ)上將writable:false
in操作符,檢查屬性是否存在對(duì)象里或是[[Prototype]]原型鏈上
Object.hasOwnProperty,只會(huì)檢查對(duì)象
問題:myObject.hasOwnProperty()可能會(huì)報(bào)錯(cuò),myObject可能是Object.create(null)生成不帶[[Prototype]]原型鏈,而Object.hasOwnProperty是由[[Prototype]]委托,所以可以這樣,Object.prototype.hasOwnProperty.call(myObject, "a")
有坑:
4 in [2,4,6] // false 4 in [2,2,6,8,0] // true
判斷是否可枚舉 myObject.propertyIsEnumerable("a")
@@iterator迭代器對(duì)象for...of被訪問的對(duì)象請(qǐng)求一個(gè)迭代器對(duì)象,然后通過.next()方法遍歷所有返回來的值
數(shù)組內(nèi)置有@@iterator,所以可以直接使用for...of。
使用內(nèi)置@@iterator遍歷數(shù)組:
var myArray = [1,2,3]; var it = myArray[Symbol.iterator](); // 返回迭代器函數(shù) it.next(); // { value: 1, done: false } it.next(); // { value: 2, done: false } it.next(); // { value: 3, done: false } it.next(); // { done: true }
普通對(duì)象不含有@@iterator,無法使用for...of,可以進(jìn)行改造,
var myObject = { a: 2, b: 3 }; Object.defineProperty(myObject, Symbol.iterator, { enumerable: false, writable: false, configuabale: false, value: function() { var o = this; var idx = 0; var ks = Object.keys(o); return { next: function() { return { value: o[ks[idx++]], done: (idx > ks.length) }; } } } }); vat it = myObject[Symbol.iterator](); it.next(); // { value: 2, done: false } it.next(); // { value: 3, done: false } it.next(); // { done: true }
個(gè)人博客地址
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/106580.html
摘要:遮蔽效應(yīng)作用域查找會(huì)在找到第一個(gè)匹配的標(biāo)識(shí)符時(shí)停止,不會(huì)繼續(xù)往上層作用域查找,這就會(huì)產(chǎn)生遮蔽效應(yīng)。會(huì)發(fā)現(xiàn)每一次輸出的都是為啥勒所有的回調(diào)函數(shù)回在循環(huán)結(jié)束后才會(huì)執(zhí)行事件循環(huán)。 三劍客 編譯,顧名思義,就是源代碼執(zhí)行前會(huì)經(jīng)歷的過程,分三個(gè)步驟, 分詞/詞法分析,將我們寫的代碼字符串分解成多個(gè)詞法單元 解析/語法分析,將詞法單元集合生成抽象語法樹(AST) 代碼生成,抽象語法樹(AST)轉(zhuǎn)...
摘要:的分句會(huì)創(chuàng)建一個(gè)塊作用域,其聲明的變量僅在中有效。而閉包的神奇作用是阻止此事發(fā)生。依然持有對(duì)該作用域的引用,而這個(gè)引用就叫做閉包。當(dāng)然,無論使用何種方式對(duì)函數(shù)類型的值進(jìn)行傳遞,當(dāng)函數(shù)在別處被調(diào)用時(shí)都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標(biāo)是誰? 比如: a = 2; RHS:誰是賦值操作的源頭? 比如: conso...
摘要:最近剛剛看完了你不知道的上卷,對(duì)有了更進(jìn)一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對(duì)象原型。附錄詞法這一章并沒有說明機(jī)制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對(duì)象類類理論類的機(jī)制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對(duì) JavaScript 有了更進(jìn)一步的了解。 《你不知道的 JavaScript》上卷由兩部...
摘要:詞法作用域的查找規(guī)則是閉包的一部分。因此的確同閉包息息相關(guān),即使本身并不會(huì)真的使用閉包。而上面的創(chuàng)建一個(gè)閉包,本質(zhì)上這是將一個(gè)塊轉(zhuǎn)換成一個(gè)可以被關(guān)閉的作用域。結(jié)合塊級(jí)作用域與閉包模塊這個(gè)模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復(fù)雜微妙技術(shù)的語言,即使是經(jīng)驗(yàn)豐富的 Jav...
摘要:如果提升改變了代碼執(zhí)行的順序,會(huì)造成非常嚴(yán)重的破壞。聲明本身會(huì)被提升,而包括函數(shù)表達(dá)式的賦值在內(nèi)的賦值操作并不會(huì)提升。要注意避免重復(fù)聲明,特別是當(dāng)普通的聲明和函數(shù)聲明混合在一起的時(shí)候,否則會(huì)引起很多危險(xiǎn)的問題 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復(fù)雜微妙技術(shù)的語言,即使是經(jīng)驗(yàn)豐富的 Ja...
閱讀 1856·2021-11-11 16:55
閱讀 1466·2019-08-30 15:54
閱讀 785·2019-08-29 15:34
閱讀 2266·2019-08-29 13:11
閱讀 2923·2019-08-26 13:28
閱讀 1893·2019-08-26 10:49
閱讀 1008·2019-08-26 10:40
閱讀 2568·2019-08-23 18:21