開(kāi)發(fā)過(guò)程中遇到的一些奇妙的事情(js):

開(kāi)發(fā)過(guò)程中遇到的一些奇妙的事情:(基礎(chǔ)知識(shí)擎浴,碰到了忘了又百度了又怕忘了就記下來(lái)了)

1. 變量、函數(shù)聲明提前:

js中變量的聲明和函數(shù)聲明會(huì)上升棵介,例如:

if ('a ' in window){
 var a =10;
console.log(true)  // true
}

var a上升到if語(yǔ)句之前樊诺。 函數(shù)的聲明優(yōu)于變量聲明,這里的優(yōu)于可以理解為晚于變量聲明后眠屎,如果函數(shù)名和變量名相同,函數(shù)聲明就能覆蓋變量聲明肆饶。

var tmp = new Date();

function f() {
  console.log(tmp);
  if (false) {
    var tmp = 'hello world';
  }
}

f(); //輸出undefined
相當(dāng)于
function f() {
var tmp;
  console.log(tmp);
  if (false) {
    tmp = 'hello world';
  }
}

es5只有函數(shù)作用域和全局作用域组力,沒(méi)有塊級(jí)作用域,因此if里面的var tmp會(huì)提升到f函數(shù)內(nèi)部的頂部

 1       function Foo() {
 2            getName = function () { console.log (1); };
 3            return this;
 4        }
 5        Foo.getName = function () { console.log (2);};
 6        Foo.prototype.getName = function () { console.log (3);};
 7        var getName = function () { console.log (4);};
 8        function getName() { console.log (5);}
 9
10        //以下輸出值為多少抖拴?
11        Foo.getName(); 
12        getName();
13        Foo().getName();
14        getName();
15        new Foo.getName();
16        new Foo().getName();
17        new new Foo().getName();

瀏覽器執(zhí)行Js程序的時(shí)候燎字,分兩步:

(1)預(yù)解析
    在代碼解讀之前發(fā)生,相當(dāng)于一個(gè)"倉(cāng)庫(kù)"阿宅,放一些東西候衍,比如var、function洒放、參數(shù)等蛉鹿。
    預(yù)解析時(shí)變量都是未定義的,函數(shù)則是整個(gè)函數(shù)塊往湿。
    預(yù)解析時(shí)遇到重名的妖异,會(huì)覆蓋。變量與函數(shù)领追,留函數(shù)他膳;函數(shù)與函數(shù),留后面解析的绒窑。
    當(dāng)代碼在一個(gè)環(huán)境中執(zhí)行時(shí)棕孙,會(huì)創(chuàng)建變量對(duì)象的一個(gè)作用域鏈。是域就要預(yù)解析些膨。

(2)執(zhí)行代碼
    代碼自上而下蟀俊,從左往右的執(zhí)行,讀到表達(dá)式時(shí)订雾,預(yù)解析倉(cāng)庫(kù)中的東西發(fā)生改變肢预。
Foo.getName(); //2 
    相當(dāng)于執(zhí)行第5行的console
    
getName(); //4
    預(yù)解析里直接取,相當(dāng)于執(zhí)行第7行的console
    
Foo().getName(); // 1
首先Foo().getName()與Foo.getName()有什么差別呢洼哎,差別就在于Foo()與Foo烫映,F(xiàn)oo()是已經(jīng)把 
Foo()的內(nèi)容執(zhí)行了一遍的,F(xiàn)oo則是一個(gè)函數(shù)變量谱净,F(xiàn)oo()里面return this;窑邦,這里鏈?zhǔn)秸{(diào)用的用法,
詳細(xì)的介紹可以搜一下壕探,F(xiàn)oo.getName() 中 getName()是Foo的屬性,但是Foo().getName()中郊丛,
getName()不是Foo()的屬性李请,而是全局變量var getName = function(){return(4);};瞧筛,
Foo().getName()的意思是Foo()執(zhí)行完后,回到全局中导盅,再調(diào)用getName()较幌,這樣就叫鏈?zhǔn)秸{(diào)用。
那為什么結(jié)果是1不是4白翻,因?yàn)镕oo()執(zhí)行的結(jié)果使 getName = function(){return(1);};乍炉,
所以再次調(diào)用getName(),結(jié)果就是1滤馍,
    
getName(); //1
    跟window.getName()一樣岛琼,
    當(dāng)于執(zhí)行第2行的console
    
new Foo.getName(); // 2
    執(zhí)行第5行的Foo.getName(),

    new操作符調(diào)用構(gòu)造函數(shù)創(chuàng)建對(duì)象的步驟?
    (1)創(chuàng)建一個(gè)新對(duì)象巢株;
    (2)將構(gòu)造函數(shù)的作用域賦給新對(duì)象(因此this就指向了這個(gè)新對(duì)象)
    (3)執(zhí)行構(gòu)造函數(shù)中的代碼(為這個(gè)新對(duì)象添加屬性)
    (4)返回新對(duì)象
    點(diǎn)(.)的優(yōu)先級(jí)高于new操作槐瑞,遂相當(dāng)于是:
        new (Foo.getName)();
    new操作符是要執(zhí)行構(gòu)造函數(shù)中的代碼的;
    所以實(shí)際上將getName函數(shù)作為了構(gòu)造函數(shù)來(lái)執(zhí)行阁苞,遂打印2

new Foo().getName(); // 3
    Foo()執(zhí)行返回this困檩,此時(shí)this指向new出來(lái)的新實(shí)例對(duì)象,
    實(shí)例對(duì)象從本身找不到getName屬性那槽,順著原型鏈找到第6行的getName悼沿,打印3
    執(zhí)行第6行console

new new Foo().getName(); // 3
    以實(shí)例的getName方法為構(gòu)造函數(shù)new實(shí)例,執(zhí)行構(gòu)造函數(shù)骚灸,打印3
    執(zhí)行第6行

P.s 這道題目網(wǎng)上有很多显沈。具體出處找不到了,但是很有意思逢唤。

2. 遍歷節(jié)點(diǎn)的Js規(guī)范:
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
      doSomething(divs[i]);
}

這樣的操作拉讯,假如獲取節(jié)點(diǎn)長(zhǎng)度(divs.length)的復(fù)雜度是O(n),獲取某個(gè)子節(jié)點(diǎn)的復(fù)雜度也是O(n)鳖藕,則由于每次要計(jì)算節(jié)點(diǎn)長(zhǎng)度魔慷,因而遍歷一遍所有節(jié)點(diǎn),這個(gè)算法的時(shí)間復(fù)雜度就為O(n^2)著恩。用以下方法可降低時(shí)間復(fù)雜度:

var divs = document.getElementsByTagName('div');
var size = divs.length;
for (var i = 0; i < size; i++) {
    doSomething(divs[i]);
}

這里先把節(jié)點(diǎn)長(zhǎng)度存到一個(gè)局部變量中院尔,以后每次循環(huán)不再計(jì)算節(jié)點(diǎn)長(zhǎng)度,因此總的時(shí)間復(fù)雜度變?yōu)榱薕(n) + 1;
TGuildeJs規(guī)范

3. 事件監(jiān)聽(tīng):
<ul id="list">
  <li id="item1">item1</li>
  <li id="item2">item2</li>
  <li id="item3">item3</li>
  <li id="item4">item4</li>
</ul>

a. 以前為li綁定事件都是獲取li節(jié)點(diǎn)喉誊,然后綁定事件:

window.onload=function(){
  var ulNode=document.getElementById("list");
  var liNodes=ulNode.childNodes||ulNode.children;
  for(var i=0;i<liNodes.length;i++){
    liNodes[i].addEventListener('click',function(e){
      alert(e.target.innerHTML);
    },false);
  }
}

由上可以看出來(lái)邀摆,假如不停的刪除或添加li,則function()也要不停的更改操作伍茄,易出錯(cuò)栋盹,因此推薦使用事件代理。在傳統(tǒng)的事件處理中敷矫,你按照需要為每一個(gè)元素添加或者是刪除事件處理器例获。然而汉额,事件處理器將有可能導(dǎo)致內(nèi)存泄露或者是性能下降——你用得越多這種風(fēng)險(xiǎn)就越大。JavaScript事件代理則是一種簡(jiǎn)單的技巧榨汤,通過(guò)它你可以把事件處理器添加到一個(gè)父級(jí)元素上蠕搜,這樣就避免了把事件處理器添加到多個(gè)子級(jí)元素上。
b. 使用事件代理
事件代理用到了兩個(gè)在JavaSciprt事件中兩個(gè)特性:事件冒泡以及目標(biāo)元素收壕。使用事件代理妓灌,我們可以把事件處理器添加到一個(gè)元素上,等待一個(gè)事件從它的子級(jí)元素里冒泡上來(lái)蜜宪,并且可以得知這個(gè)事件是從哪個(gè)元素開(kāi)始的虫埂。

window.onload=function(){
  e = e || window.event;/*在函數(shù)體內(nèi)不用使用event = event || window.event; 來(lái)標(biāo)準(zhǔn)化Event 對(duì)象;*/
  target = e.target || e.srcElement;
  var ulNode=document.getElementById("list");
  ulNode.addEventListener('click',function(e){
       if(target.nodeName.toUpperCase()=="LI"){/*獲取目標(biāo)元素端壳,判斷目標(biāo)事件是否為li*/
         alert(e.target.innerHTML);
       }
     },false);/*false 默認(rèn)參數(shù)告丢,冒泡階段*/
};
4. 一次完整ajax是如何實(shí)現(xiàn)的?

5. 一次完整Http請(qǐng)求是如何實(shí)現(xiàn)的损谦?

6. 對(duì)跨作用域的變量處理建議:
  • 將常用的跨作用域變量?jī)?chǔ)存在局部變量中岖免,然后直接訪問(wèn)局部變量。
7. 關(guān)于作用域鏈
  • 每一個(gè)JS函數(shù)都表示一個(gè)對(duì)象照捡,F(xiàn)unction是對(duì)象的一個(gè)實(shí)例颅湘,因此Function對(duì)象擁有可以訪問(wèn)的屬性、方法栗精,和不可以訪問(wèn)僅供JS引擎存取的內(nèi)部屬性闯参。其中一個(gè)內(nèi)部屬性是[[scope]];
    [[scope]]包含了一個(gè)函數(shù)被創(chuàng)建的作用域?qū)ο蟮募希@個(gè)集合就是作用域鏈悲立,作用域鏈決定了函數(shù)有權(quán)訪問(wèn)哪些變量和方法鹿寨,作用域鏈中每個(gè)對(duì)象成為可變對(duì)象。
function sum(x,y){
     var a =10;
     return x+y+a;
}
sum(2,3)
  1. 當(dāng)sum函數(shù)創(chuàng)建之后薪夕,sum函數(shù)的內(nèi)部屬性[[scope]]所包含的作用域鏈插入了一個(gè)可變對(duì)象脚草,此時(shí)的可變對(duì)象又稱為全局對(duì)象,包含著
    諸如window原献,navigator馏慨,document,sum本身 等等姑隅。
  2. 當(dāng)sum(2,3)執(zhí)行時(shí)写隶,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境,多次執(zhí)行函數(shù)會(huì)創(chuàng)建多個(gè)執(zhí)行環(huán)境讲仰,函數(shù)執(zhí)行完畢后慕趴,執(zhí)行環(huán)境會(huì)自動(dòng)銷毀。
    每個(gè)執(zhí)行環(huán)境都有自己的作用域鏈,用于解析標(biāo)識(shí)符秩贰,當(dāng)執(zhí)行環(huán)境被創(chuàng)建時(shí)霹俺,它的作用域鏈初始化為當(dāng)前函數(shù)的[[scope]]屬性中的對(duì)象柔吼,函數(shù)的作用域鏈會(huì)插入一個(gè)可變對(duì)象毒费,此時(shí)的可變對(duì)象稱為活動(dòng)對(duì)象,包含著所有函數(shù)內(nèi)部的局部變量愈魏,參數(shù)觅玻,參數(shù)集合(arguments),this培漏。當(dāng)執(zhí)行環(huán)境被銷毀時(shí)溪厘,活動(dòng)對(duì)象也被銷毀。
  3. 活動(dòng)對(duì)象會(huì)被推入作用域的最前端牌柄,因此在函數(shù)內(nèi)部訪問(wèn)變量的時(shí)候會(huì)先反問(wèn)活動(dòng)對(duì)象畸悬,再訪問(wèn)外部的對(duì)象,因此才會(huì)有第6條的內(nèi)容珊佣。
8. 閉包:

在理解上述的關(guān)于作用域鏈的描述之后蹋宦,閉包會(huì)更容易理解。
常見(jiàn)閉包場(chǎng)景咒锻,就是函數(shù)A內(nèi)部返回一個(gè)函數(shù)B冷冗,這樣函數(shù)B可以訪問(wèn)函數(shù)A內(nèi)部的變量,即使在函數(shù)A執(zhí)行完之后自身的執(zhí)行環(huán)境被銷毀惑艇。

function sum(a,b){
return function add(){
    return a+b;
  }
}
var t = sum(1,2) 
t();
  1. 當(dāng)sum函數(shù)創(chuàng)建時(shí)蒿辙,會(huì)產(chǎn)生一個(gè)全局對(duì)象。
  2. 當(dāng)sum(1,2)執(zhí)行時(shí)滨巴,會(huì)產(chǎn)生一個(gè)活動(dòng)對(duì)象思灌,包含a,b。
  3. 當(dāng)add函數(shù)創(chuàng)建時(shí)(及閉包創(chuàng)建)恭取,它的[[scope]]屬性被初始化為以上的兩個(gè)對(duì)象泰偿。
  4. 當(dāng)t()執(zhí)行時(shí)(及閉包執(zhí)行),會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境秽荤,它的作用域鏈與屬性[[scope]]中所引用的兩個(gè)相同的作用域鏈對(duì)象一起被初始化甜奄,然后一個(gè)活動(dòng)對(duì)象被閉包自身創(chuàng)建。
  5. 此時(shí)閉包的作用域鏈包含3個(gè)對(duì)象窃款,一個(gè)全局對(duì)象课兄,一個(gè)sum活動(dòng)對(duì)象,一個(gè)自身的活動(dòng)對(duì)象晨继。所以閉包可以訪問(wèn)外部函數(shù)的屬性烟阐。
  6. 外部函數(shù)執(zhí)行環(huán)境被銷毀,但由于外部函數(shù)的活動(dòng)對(duì)象被閉包引用,因此這些活動(dòng)對(duì)象無(wú)法被銷毀蜒茄,這意味著腳本中的閉包需要更多內(nèi)存消耗唉擂。
9. 關(guān)于使用"use strict"

對(duì)于這個(gè)問(wèn)題,既簡(jiǎn)要又最重要的答案是檀葛,use strict 是一種在JavaScript代碼運(yùn)行時(shí)自動(dòng)實(shí)行更嚴(yán)格解析和錯(cuò)誤處理的方法玩祟。那些被忽略或默默失敗了的代碼錯(cuò)誤,會(huì)產(chǎn)生錯(cuò)誤或拋出異常屿聋。通常而言空扎,這是一個(gè)很好的做法。

嚴(yán)格模式的一些主要優(yōu)點(diǎn)包括:

  1. 使調(diào)試更加容易润讥。那些被忽略或默默失敗了的代碼錯(cuò)誤转锈,會(huì)產(chǎn)生錯(cuò)誤或拋出異常,因此盡早提醒你代碼中的問(wèn)題楚殿,你才能更快地指引到它們的源代碼撮慨。
  2. 防止意外的全局變量。如果沒(méi)有嚴(yán)格模式脆粥,將值分配給一個(gè)未聲明的變量會(huì)自動(dòng)創(chuàng)建該名稱的全局變量砌溺。這是JavaScript中最常見(jiàn)的錯(cuò)誤之一。在嚴(yán)格模式下冠绢,這樣做的話會(huì)拋出錯(cuò)誤抚吠。
"use strict"
function f(){
  b=2;
  console.log(b)  //ERROR
}
f();
  1. 消除 this 強(qiáng)制。如果沒(méi)有嚴(yán)格模式弟胀,引用null或未定義的值到 this 值會(huì)自動(dòng)強(qiáng)制到全局變量楷力。這可能會(huì)導(dǎo)致許多令人頭痛的問(wèn)題和讓人恨不得拔自己頭發(fā)的bug。在嚴(yán)格模式下孵户,引用 null或未定義的 this 值會(huì)拋出錯(cuò)誤萧朝。
  2. 不允許重復(fù)的屬性名稱或參數(shù)值。當(dāng)檢測(cè)到對(duì)象(例如夏哭,var object = {foo: "bar", foo: "baz"};)中重復(fù)命名的屬性检柬,或檢測(cè)到函數(shù)中(例如,function foo(val1, val2, val1){})重復(fù)命名的參數(shù)時(shí)竖配,嚴(yán)格模式會(huì)拋出錯(cuò)誤何址,因此捕捉幾乎可以肯定是代碼中的bug可以避免浪費(fèi)大量的跟蹤時(shí)間。
  3. 使eval() 更安全进胯。在嚴(yán)格模式和非嚴(yán)格模式下用爪,eval() 的行為方式有所不同。最顯而易見(jiàn)的是胁镐,在嚴(yán)格模式下偎血,變量和聲明在 eval() 語(yǔ)句內(nèi)部的函數(shù)不會(huì)在包含范圍內(nèi)創(chuàng)建(它們會(huì)在非嚴(yán)格模式下的包含范圍中被創(chuàng)建诸衔,這也是一個(gè)常見(jiàn)的問(wèn)題源)。
  4. 在 delete使用無(wú)效時(shí)拋出錯(cuò)誤颇玷。delete操作符(用于從對(duì)象中刪除屬性)不能用在對(duì)象不可配置的屬性上笨农。當(dāng)試圖刪除一個(gè)不可配置的屬性時(shí),非嚴(yán)格代碼將默默地失敗帖渠,而嚴(yán)格模式將在這樣的情況下拋出異常谒亦。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市阿弃,隨后出現(xiàn)的幾起案子诊霹,更是在濱河造成了極大的恐慌羞延,老刑警劉巖渣淳,帶你破解...
    沈念sama閱讀 221,820評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異伴箩,居然都是意外死亡入愧,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,648評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門嗤谚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)棺蛛,“玉大人,你說(shuō)我怎么就攤上這事巩步∨陨蓿” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 168,324評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵椅野,是天一觀的道長(zhǎng)终畅。 經(jīng)常有香客問(wèn)我,道長(zhǎng)竟闪,這世上最難降的妖魔是什么离福? 我笑而不...
    開(kāi)封第一講書人閱讀 59,714評(píng)論 1 297
  • 正文 為了忘掉前任,我火速辦了婚禮炼蛤,結(jié)果婚禮上妖爷,老公的妹妹穿的比我還像新娘。我一直安慰自己理朋,他們只是感情好絮识,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,724評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著嗽上,像睡著了一般次舌。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上炸裆,一...
    開(kāi)封第一講書人閱讀 52,328評(píng)論 1 310
  • 那天垃它,我揣著相機(jī)與錄音,去河邊找鬼。 笑死国拇,一個(gè)胖子當(dāng)著我的面吹牛洛史,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播酱吝,決...
    沈念sama閱讀 40,897評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼也殖,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了务热?” 一聲冷哼從身側(cè)響起忆嗜,我...
    開(kāi)封第一講書人閱讀 39,804評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎崎岂,沒(méi)想到半個(gè)月后捆毫,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,345評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡冲甘,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,431評(píng)論 3 340
  • 正文 我和宋清朗相戀三年绩卤,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片江醇。...
    茶點(diǎn)故事閱讀 40,561評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡濒憋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出陶夜,到底是詐尸還是另有隱情凛驮,我是刑警寧澤,帶...
    沈念sama閱讀 36,238評(píng)論 5 350
  • 正文 年R本政府宣布条辟,位于F島的核電站黔夭,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捂贿。R本人自食惡果不足惜纠修,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,928評(píng)論 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望厂僧。 院中可真熱鬧扣草,春花似錦、人聲如沸颜屠。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,417評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甫窟。三九已至密浑,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間粗井,已是汗流浹背尔破。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,528評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工街图, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懒构。 一個(gè)月前我還...
    沈念sama閱讀 48,983評(píng)論 3 376
  • 正文 我出身青樓餐济,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親胆剧。 傳聞我的和親對(duì)象是個(gè)殘疾皇子絮姆,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,573評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容