最近項(xiàng)目产喉,一直在研究使用新的框架捂掰,新的工具,結(jié)果發(fā)現(xiàn)學(xué)習(xí)的速度還沒(méi)有輪子出現(xiàn)的速度快曾沈,就拿webpack來(lái)說(shuō)这嚣,1.0都還沒(méi)有掌握,2.0就出來(lái)了塞俱,無(wú)力感突現(xiàn)姐帚,一直在跟隨著別人的腳步在前進(jìn),都沒(méi)有自己的東西敛腌,所以內(nèi)功才是一切卧土,內(nèi)功強(qiáng)大,自己寫(xiě)一個(gè)框架像樊,也不是不可尤莺。不然你連人家的源碼都不懂,只會(huì)用又有什么用呢生棍,明天換一個(gè)框架颤霎,或者換一個(gè)公司,你又要從頭開(kāi)始涂滴,你的競(jìng)爭(zhēng)力又在何方友酱。
-
作用域
1,LHS(賦值操作)和RHS(取值操作)查詢都會(huì)在當(dāng)前執(zhí)行作用域開(kāi)始柔纵,如果沒(méi)有找到缔杉,就會(huì)向上級(jí)作用域繼續(xù)查找目標(biāo)標(biāo)識(shí)符,這樣每次上升一級(jí)搁料,最后抵達(dá)全局作用域或详。
2系羞,不成功的RHS引用會(huì)拋出ReferenceError異常,不成功的LHS引用會(huì)導(dǎo)致自動(dòng)隱式的創(chuàng)建全局變量(非嚴(yán)格模式下)霸琴,或者拋出ReferenceError異常(嚴(yán)格模式下)
-
詞法作用域##
詞法作用域完全由寫(xiě)代碼期間函數(shù)聲明的位置來(lái)定義
function foo(a) {
var b = a * 2;
function bar(c) {
console.log( a, b, c );
}
bar(b * 3);
}
foo( 2 ); // 2 4 12
對(duì)于console而言椒振,會(huì)先查找最內(nèi)部的作用域,引擎在這里無(wú)法找到a,因此就會(huì)去上一層作用域中查找梧乘。作用域查找會(huì)在找到第一個(gè)匹配的標(biāo)識(shí)符時(shí)停止澎迎,所以在多層嵌套的作用域中可以定義同名的標(biāo)識(shí)符,這叫做遮蔽效應(yīng)(內(nèi)部的標(biāo)識(shí)符遮蔽了外部的標(biāo)識(shí)符)
function foo(str, a) {
eval( str ); // 欺騙!选调,在運(yùn)行時(shí)就相當(dāng)于var b= 3,遮蔽了外部的b
// 但是在嚴(yán)格模式下夹供,eval運(yùn)行時(shí),有自己的作用域学歧,無(wú)法修改所在的作用域
console.log( a, b );
}
var b = 2;
foo( "var b = 3;", 1 ); // 1 3
function foo(obj) {
with (obj) {
a = 2;
}
}
var o1 = {
a: 3
};
var o2 = {
b: 3
};
foo( o1 );
console.log( o1.a ); // 2
foo( o2 );
console.log( o2.a ); // undefined
console.log( a ); // 2 -- 不好罩引,a被泄露到全局作用域上了!
//當(dāng)我們傳遞o1給with時(shí),with所聲明的作用域是o1,而這個(gè)作用域中含有一個(gè)相符的標(biāo)識(shí)符枝笨,但是我們將o2作為作用域時(shí)袁铐,其中并沒(méi)有a標(biāo)識(shí)符,因此進(jìn)行了正常的LHS查找
使用eval和with可以欺騙詞法作用域横浑,但是會(huì)導(dǎo)致性能的下降剔桨,所以不要使用,同時(shí)因?yàn)閖s引擎會(huì)在編譯階段進(jìn)行數(shù)項(xiàng)的優(yōu)化徙融,但是對(duì)于未知的代碼時(shí)優(yōu)化不了的
-
函數(shù)作用域和塊作用域
1洒缀,在軟件設(shè)計(jì)中,應(yīng)該最小限度的暴露必要內(nèi)容欺冀,而將其他的內(nèi)容都隱藏起來(lái)树绩,比如某個(gè)模塊或?qū)ο蟮腁PI,
2隐轩,(function(){})()和(function(){}())是一樣的東西饺饭,都叫做立即執(zhí)行函數(shù)表達(dá)式(IIFE),看個(gè)人習(xí)慣,
3,在try/catch的catch分局中會(huì)創(chuàng)建一個(gè)作用域
4,
-
提升
1职车,js存在預(yù)編譯階段瘫俊,此時(shí)會(huì)將函數(shù)聲明和變量提升,并且函數(shù)會(huì)在變量之前悴灵,同事若是重復(fù)的聲明將會(huì)忽略
-
閉包
1,無(wú)論通過(guò)何種手段將內(nèi)部函數(shù)傳遞到所在的詞法作用域以外扛芽,他都會(huì)持有對(duì)原始定義作用域的引用,無(wú)論在何處執(zhí)行這個(gè)函數(shù)都會(huì)使用閉包积瞒,內(nèi)部的變量都不會(huì)銷(xiāo)毀川尖,因?yàn)殚]包需要使用,最常見(jiàn)的就是回調(diào)函數(shù)茫孔,和setTimeout,
2,延遲函數(shù)的回調(diào)會(huì)在循環(huán)結(jié)束后才執(zhí)行空厌,會(huì)先把當(dāng)前的同步執(zhí)行完庐船,
3银酬,現(xiàn)在大多數(shù)的模塊依賴加載/管理器的本質(zhì)上都是將這種模塊定義封裝進(jìn)一個(gè)友好的API中嘲更,一下是核心的原理
var MyModules = (function Manager(){
var modules = []
// name: 模塊名稱
// deps:模塊依賴
// impl: 模塊實(shí)體
function define(name,deps,impl){
// 得到所有依賴,當(dāng)前依賴的東西必須在之前已經(jīng)定義好的
for(var i=0;i<deps.length;i++){
deps[i] = modules[deps[i]]
}
// 定義模塊揩瞪,將所有依賴傳入當(dāng)前的模塊實(shí)體中赋朦,這樣模塊便可以使用依賴
// apply會(huì)直接執(zhí)行函數(shù),然后得到模塊暴露出來(lái)的API
modules[name] = impl.apply(impl,deps)
}
function get(name){
return modules[name]
}
// 暴露API
return {
define: define,
get: get
}
})()
4李破,模塊文件中的內(nèi)容會(huì)被當(dāng)做好像包含在作用域閉包中一樣來(lái)處理宠哄。
-
this
使用new來(lái)調(diào)用函數(shù),會(huì)自動(dòng)執(zhí)行下面的操作
1,創(chuàng)建一個(gè)全新的對(duì)象
2,這個(gè)對(duì)象會(huì)被執(zhí)行[[Prototype]]連接
3,這個(gè)新對(duì)象會(huì)綁定到函數(shù)調(diào)用的this
4,如果函數(shù)內(nèi)部沒(méi)有返回嗤攻,那么自動(dòng)返回這個(gè)新對(duì)象
1毛嫉,字符串,數(shù)值妇菱,布爾字面量在需要的時(shí)候會(huì)自動(dòng)轉(zhuǎn)換為對(duì)應(yīng)的對(duì)象
2承粤,object.assign使用=復(fù)制,所以引用的東西復(fù)制過(guò)來(lái)還是引用
3闯团,var myobject = Object.create(anotherobject)//以這個(gè)對(duì)象為原型創(chuàng)建一個(gè)對(duì)象
var obj = Object.create(null)得到的對(duì)象沒(méi)有_proto_,存儲(chǔ)數(shù)據(jù)最好了辛臊。
-
原型,委托
這里的原型概念確實(shí)拓展了以前的理解
常見(jiàn)的類(lèi)的實(shí)現(xiàn)
function Foo(who){
this.me = who
}
Foo.prototype.identify = function(){
return 'I am '+ this.me
}
function Bar(who){
Foo.call(this,who)
}
// 慚愧房交,以前直接=彻舰,因?yàn)槭且茫圆缓线壿?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()
這種實(shí)現(xiàn)情況下候味,他的關(guān)系圖如下(良心出品):
1刃唤,因?yàn)閎ar的原型對(duì)象中沒(méi)有constructor所以去原型鏈中找到了Foo,b1,b2也是一樣
2白群,F(xiàn)oo,Bar都是Function 的一個(gè)實(shí)例(函數(shù)也是一個(gè)對(duì)象)尚胞,包括function Object()也是,所以他們的constructor都指向Function 對(duì)象川抡,而proto都指向Function.prototype,
使用委托風(fēng)格實(shí)現(xiàn)的代碼:
Foo = {
init: function(who){
this.me = who
},
identify: function(){
return 'I am '+this.me
}
}
Bar = Object.create(Foo)
Bar.speak = function(){
alert('Hello,'+this.identify()+'.')
}
var b1 = Object.create(Bar)
b1.init('b1')
var b2 = Object.create(Bar)
b2.init('b2')
b1.speak()
b2.speak()
關(guān)系圖如下:
實(shí)現(xiàn)方式比較簡(jiǎn)單辐真,就是一路的使用原型鏈去委托,找不到的話崖堤,就去上一級(jí)尋找侍咱。
還是習(xí)慣于使用傳統(tǒng)的方式,但是委托的方式還是很大拓展的思維
-
嚴(yán)格模式的限制
變量必須聲明后再使用
函數(shù)的參數(shù)不能有同名屬性密幔,否則報(bào)錯(cuò)
不能使用with語(yǔ)句
不能對(duì)只讀屬性賦值楔脯,否則報(bào)錯(cuò)
不能使用前綴0表示八進(jìn)制數(shù),否則報(bào)錯(cuò)
不能刪除不可刪除的屬性胯甩,否則報(bào)錯(cuò)
不能刪除變量delete prop昧廷,會(huì)報(bào)錯(cuò)堪嫂,只能刪除屬性delete global[prop]
eval不會(huì)在它的外層作用域引入變量
eval和arguments不能被重新賦值
arguments不會(huì)自動(dòng)反映函數(shù)參數(shù)的變化
不能使用arguments.callee
不能使用arguments.caller
禁止this指向全局對(duì)象
不能使用fn.caller和fn.arguments獲取函數(shù)調(diào)用的堆棧
增加了保留字(比如protected、static和interface)
-
es6模塊
1,代碼是在模塊作用域之中運(yùn)行木柬,而不是在全局作用域運(yùn)行皆串。模塊內(nèi)部的頂層變量,外部不可見(jiàn)眉枕。
2,模塊腳本自動(dòng)采用嚴(yán)格模式恶复,不管有沒(méi)有聲明use strict。
3,模塊之中速挑,可以使用import命令加載其他模塊(.js后綴不可省略谤牡,需要提供絕對(duì) URL 或相對(duì) URL),也可以使用export命令輸出對(duì)外接口姥宝。
4,模塊之中翅萤,頂層的this關(guān)鍵字返回undefined,而不是指向window腊满。也就是說(shuō)套么,在模塊頂層使用this關(guān)鍵字,是無(wú)意義的糜烹。
5,同一個(gè)模塊如果加載多次违诗,將只執(zhí)行一次。