javascript學習
阿新 • • 發佈:2020-08-18
//1.undefined 是派生自null的 //alert(undefined == null); //alert(undefined === null); ////結果 true false //2.建議還是養成編碼的規範, //不要忘記初始化變數。 //var box; //var car = null; //alert(typeof box == typeof car) //結果false //var hello = 'Hello World!'; //var hello2 = Boolean(hello); //alert(typeof hello);////String型別 //上面是一種顯示轉換,屬於強制性轉換。 //而實際應用中,還有一種隱式轉換。 //比如,在if 條件語句裡面的條件判斷,就存在隱式轉換。 //var hello = 'Hello World!'; //if (hello) { // alert('如果條件為true,就執行我這條!');//結果:true //} else { // alert('如果條件為false,就執行我這條!'); //} //以下是其他型別轉換成Boolean型別規則 //資料型別轉換為true 的值轉換為false 的值//Boolean true false //String 任何非空字串空字串 //Number 任何非零數字值(包括無窮大) 0 和NaN //Object 任何物件null //Undefined undefined //要想確定一個數值到底是否超過了規定範圍, //可以使用isFinite()函式。如果沒有超過, //返回true,超過了返回false。 //可以通過Number.NaN 得到NaN 值, //任何與NaN 進行運算的結果均為NaN, //NaN 與自身不相等(NaN 不與任何值相等)。 //alert(Number.NaN); //NaN//alert(NaN+1); //NaN //alert(NaN == NaN) //false //繼承 //function Box() { // this.name = '測試'; // this.age = 18; // this.height = 171; //} //function Test() { // this.sex = '男'; //} //Test.prototype = new Box(); //var test = new Test(); //alert(test.age); //function Box(name, age) { // alert("姓名:" + name + "年齡:" + age); //} //Box("asd", 12); //function Box(name,age) //{ // return '你的姓名:' + name + ',年齡' + age; //} //alert(Box('測試', 18)); //function Box(num1,num2) { // return num1 * num2; //} //var num = Box(15, 15); //alert(num); //function Box(num) { // if (num < 50) { // return num; // } // else { // return 100; // } //} //alert(Box(10)); //alert(Box(80)); //function Box() { // return arguments[0] + '|' + arguments[1];//得到每次引數的值 //} //alert(Box(1, 2, 3, 4, 5, 6));//傳遞引數 //function Box() { // return arguments.length;//得到6 //} //alert(Box(1, 2, 3, 4, 56, 7)); //function box() { // var sum = 0; // if (arguments.length == 0) { // return sum;//如果沒有引數就返回0; // } // for (var i = 0; i < arguments.length; i++) {//如果有,則累加 // sum = sum + arguments[i]; // } // return sum;//返回累加結果 //} //alert(box(2, 6541, 3, 1)); //var box = new Object(); //box.name='測試name'; //box.age = 28; //alert(box['name']) //alert(box['age']) //delete box.age;//刪除屬性 //alert(box['name']) //alert(box.age)//undefined // var box = [ //{ //第一個元素是一個物件 // name: '李炎恢', // age: 28, // run: function () { // return 'run 了'; // } //}, //['馬雲', '李彥巨集', new Object()],//第二個元素是陣列 //'江蘇', //第三個元素是字串 //25 + 25, //第四個元素是數值 //new Array(1, 2, 3) //第五個元素是陣列 // ]; //var box = ['李炎恢', 28, '鹽城']; //當前陣列 //var box2 = box.slice(1); //box.slice(1,3),2-4 之間的元素 //alert(box2); //28,鹽城 //alert(box); //當前陣列 //splice 中的刪除功能: //var box = ['李炎恢', 28, '鹽城']; //當前陣列 //var box2 = box.splice(0,2); //擷取前兩個元素 //alert(box2); //返回擷取的元素 //alert(box); //當前陣列被擷取的元素被刪除 //splice 中的插入功能: //var box = ['李炎恢', 28, '鹽城']; //當前陣列 //var box2 = box.splice(1, 0, '計算機程式設計', '江蘇'); //沒有擷取,但插入了兩條 //alert(box2); //在第2 個位置插入兩條 //alert(box); //輸出 //splice 中的替換功能: //var box = ['李炎恢', 28, '鹽城']; //當前陣列 //var box2 = box.splice(1, 1, 100); //alert(box2); //alert(box); //Date: //var box = new Date(Date.UTC(2011, 11, 5, 15, 13, 16)); //alert('toString:' + box.toString()); //alert('toLocaleString:' + box.toLocaleString()); //按本地格式輸出 //PS:這兩個方法在不同瀏覽器顯示的效果又不一樣,但不用擔心,這兩個方法只是在 //除錯比較有用,在顯示時間和日期上,沒什麼價值。valueOf()方法顯示毫秒數。 //日期格式化方法 //Date 型別還有一些專門用於將日期格式化為字串的方法。 //var box = new Date(); //alert(box.toDateString()); //以特定的格式顯示星期幾、月、日和年 //alert(box.toTimeString()); //以特定的格式顯示時、分、秒和時區 //alert(box.toLocaleDateString()); //以特定地區格式顯示星期幾、月、日和年 //alert(box.toLocaleTimeString()); //以特定地區格式顯示時、分、秒和時區 //alert(box.toUTCString()); //以特定的格式顯示完整的UTC 日期。 //alert(box.getTime()); //獲取日期的毫秒數,和valueOf()返回一致 //alert(box.setTime(100)); //以毫秒數設定日期,會改變整個日期 //alert(box.getFullYear()); //獲取四位年份 //alert(box.setFullYear(2012)); //設定四位年份,返回的是毫秒數 //alert(box.getMonth()); //獲取月份,沒指定月份,從0 開始算起 //alert(box.setMonth(11)); //設定月份 //alert(box.getDate()); //獲取日期 //alert(box.setDate(8)); //設定日期,返回毫秒數 //alert(box.getDay()); //返回星期幾,0 表示星期日,6 表示星期六 //alert(box.setDay(2)); //設定星期幾 //alert(box.getHours()); //返回時 //alert(box.setHours(12)); //設定時 //alert(box.getMinutes()); //返回分鐘 //alert(box.setMinutes(22)); //設定分鐘 //alert(box.getSeconds()); //返回秒數 //alert(box.setSeconds(44)); //設定秒數 //alert(box.getMilliseconds()); //返回毫秒數 //alert(box.setMilliseconds()); //設定毫秒數 //alert(box.getTimezoneOffset()); //返回本地時間和UTC 時間相差的分鐘數 //alert(/box/i.test('This is a Box!')); //alert(/box/i.exec('This is a Box!')); //除了test()和exec()方法,String 物件也提供了4 個使用正則表示式的方法。 //String 物件中的正則表示式方法 //方法 含義 //match(pattern) 返回pattern 中的子串或null //replace(pattern, replacement) 用replacement 替換pattern //search(pattern) 返回字串中pattern 開始位置 //split(pattern) 返回字串按指定pattern 拆分的陣列 /*使用match 方法獲取獲取匹配陣列*/ //var pattern = /box/ig; //var str = 'This is a Box!,That is a Box too'; //alert(str.match(pattern));//匹配到兩個Box,Box //alert(str.match(pattern).length);//獲取陣列的長度 2 /*使用search來查詢匹配資料*/ //var pattern = /box/ig; //var str = "This is a Box!,That is Box too"; //alert(str.search(pattern));//查詢到返回位置,否則返回-1; //PS:因為search方法查詢到即返回,也就是說無需g全域性. ///*使用replace 替換匹配到的資料*/ //var pattern = /box/ig; //var str = 'This is a Box!,That is a Box too'; //alert(str.replace(pattern, 'Tom')); //將Box 替換成了Tom //var pattern = / /ig; //var str = 'This is a Box!,That is a Box too'; //alert(str.split(pattern)); //將空格拆開分組成陣列 //RegExp物件的靜態屬性 //屬性短名 含義 //input $_ 當前被匹配的字串 //lastMatch $& 最後一個匹配字串 //lastParen $+ 最後一對圓括號內的匹配子串 //leftContext $` 最後一次匹配前的子串 //multiline $* 用於指定是否所有的表示式都用於多行的布林值 //rightContext $' 在上次匹配之後的子串 /*使用靜態屬性*/ //var pattern = /(g)oogle/ig; //var str = 'This is google!'; //pattern.test(str); //執行一下 //alert(RegExp.input); //This is google! //alert(RegExp.leftContext); //This is //alert(RegExp.rightContext); //! //alert(RegExp.lastMatch); //google //alert(RegExp.lastParen); //g //alert(RegExp.multiline); //false //global Boolean 值,表示g 是否已設定 //ignoreCase Boolean 值,表示i 是否已設定 //lastIndex 整數,代表下次匹配將從哪裡字元位置開始 //multiline Boolean 值,表示m 是否已設定 //Source 正則表示式的源字串形式 /*使用例項屬性*/ //var pattern = /google/ig; //alert(pattern.global); //true,是否全域性了 //alert(pattern.ignoreCase); //true,是否忽略大小寫 //alert(pattern.multiline); //false,是否支援換行 //alert(pattern.lastIndex); //0,下次的匹配位置 //alert(pattern.source); //google,正則表示式的源字串 //var pattern = /google/g; //var str = 'google google google'; //pattern.test(str); //google,匹配第一次 //alert(pattern.lastIndex); //6,第二次匹配的位 // 獲取控制 // 正則表示式元字元是包含特殊含義的字元。它們有一些特殊功能,可以控制匹配模式的 // 方式。反斜槓後的元字元將失去其特殊含義。 // 字元類:單個字元和數字 // 元字元/元符號匹配情況 // . 匹配除換行符外的任意字元 // [a-z0-9] 匹配括號中的字符集中的任意字元 // [^a-z0-9] 匹配任意不在括號中的字符集中的字元 //\d 匹配數字 //\D 匹配非數字,同[^0-9]相同 //\w 匹配字母和數字及_ //\W 匹配非字母和數字及_ // 字元類:空白字元 // 元字元/元符號匹配情況 //\0 匹配null 字元 //\b 匹配空格字元 //\f 匹配進紙字元 //\n 匹配換行符 //\r 匹配回車字元 //\t 匹配製表符 //\s 匹配空白字元、空格、製表符和換行符 //\S 匹配非空白字元 // 字元類:錨字元 // 元字元/元符號匹配情況 // ^ 行首匹配 // $ 行尾匹配 //\A 只有匹配字串開始處 //\b 匹配單詞邊界,詞在[]內時無效 //\B 匹配非單詞邊界 //\G 匹配當前搜尋的開始位置 //\Z 匹配字串結束處或行尾 //\z 只匹配字串結束處 // 字元類:重複字元 // 元字元/元符號匹配情況 // x? 匹配0 個或1 個x // x* 匹配0 個或任意多個x // x+ 匹配至少一個x // (xyz)+ 匹配至少一個(xyz) // x{m,n} 匹配最少m 個、最多n 個x // 字元類:替代字元 // 元字元/元符號匹配情況 // this|where|logo 匹配this 或where 或logo 中任意一個 // 字元類:記錄字元 // 元字元/元符號匹配情況 // (string) 用於反向引用的分組 //\1 或$1 匹配第一個分組中的內容 //\2 或$2 匹配第二個分組中的內容 //\3 或$3 匹配第三個分組中的內容 //var pattem = /[a-z][A-Z]+/; //var str = 'gOOGLE'; //alert(pattem.test(str)); //var pattern = /8(.*)8/; //var str = 'This is 8google8'; //var result = str.replace(pattern, '<strong>$1</strong>'); //得到替換的字串輸出 //document.write(result); // 貪婪 惰性 // + +? // ? ?? // * *? // {n} {n}? // {n,} {n,}? // {n,m} {n,m}? /*關於貪婪和惰性*/ //var pattern = /[a-z]+?/; //?號關閉了貪婪匹配,只替換了第一個 //var str = 'abcdefjhijklmnopqrstuvwxyz'; //var result = str.replace(pattern, 'xxx'); //alert(result); //var pattern = /8(.+?)8/g;//禁止了貪婪,開啟了全域性 //var str = 'This is 8google8,That is 8google8,There is 8google8'; //var result = str.replace(pattern, '<strong>$1</strong>'); //document.write(result); //var pattern = /8([^8]*)8/g;//另一種禁止貪婪 //var str = 'This is 8google8,That is 8google8,There is 8google8'; //var result = str.replace(pattern, '<strong>$1</strong>'); //document.write(result); /*使用exec 返回陣列*/ //var pattern = /^[a-z]+\s[0-9]{4}$/i; //var str = 'google 2012'; //alert(pattern.exec(str)); //返回整個字串 //var pattern = /^[a-z]+/i; //只匹配字母 //var str = 'google 2012'; //alert(pattern.exec(str)); //返回google //var pattern = /^([a-z]+)\s([0-9]{4})$/i; //使用分組 //var str = 'google 2012'; //alert(pattern.exec(str)[0]); //google 2012 //alert(pattern.exec(str)[1]); //google //alert(pattern.exec(str)[2]); //2012 ///*捕獲性分組和非捕獲性分組*/ //var pattern = /(\d+)([a-z])/; //捕獲性分組 //var str = '123abc'; //alert(pattern.exec(str)); //123a,123,a //var pattern = /(\d+)(?:[a-z])/; //非捕獲性分組 //var str = '123abc'; //alert(pattern.exec(str));//123a,123 ///*使用分組巢狀*/ //var pattern = /(A?(B?(C?)))/; //從外往內獲取 //var str = 'ABC'; //alert(pattern.exec(str)); //ABC,ABC,BC,C ///*使用前瞻捕獲*/ //var pattern = /(goo(?=gle))/; //goo 後面必須跟著gle 才能捕獲 //var str = 'google'; //alert(pattern.exec(str)); //goo,goo ///*使用特殊字元匹配*/ //var pattern = /\.\[\/b\]/; //特殊字元,用\符號轉義即可 //var str = '.[/b]'; //alert(pattern.test(str));//true ///*使用換行模式*/ //var pattern = /^\d+/mg; //啟用了換行模式 //var str = '1.baidu\n2.google\n3.bing'; //var result = str.replace(pattern, '#'); //alert(result); //1.檢查郵政編碼 //var pattern = /[1-9][0-9]{5}/; //共6 位數字,第一位不能為0 //var str = '224000'; //alert(pattern.test(str)); //2.檢查檔案壓縮包 //var pattern = /[\w]+\.zip|rar|gz/; //\w 表示所有數字和字母加下劃線 //var str = '123.zip'; //\.表示匹配.,後面是一個選擇 //alert(pattern.test(str)); ////3.刪除多餘空格 //var pattern = /\s|\/\/\w{0,}|\/\/[\u4e00-\u9fa5]{0,}/g; //g 必須全域性,才能全部匹配 ////var str = '111 222 333'; //var str = document.documentElement.innerHTML; //var result = str.replace(pattern,''); //把空格匹配成無空格 //document.write(result); ////4.刪除首尾空格 //var pattern = /^\s+/; //強制首 //var str = ' goo gle '; //var result = str.replace(pattern, ''); //pattern = /\s+$/; //強制尾 //result = result.replace(pattern, ''); //alert('|' + result + '|'); ////4.刪除首尾空格 //var pattern = /^\s*(.+?)\s*$/; //使用了非貪婪捕獲 //var str = ' google '; //alert('|' + pattern.exec(str)[1] + '|'); //var pattern = /^\s*(.+?)\s*$/; //var str = ' google '; //alert('|' + str.replace(pattern, '$1') + '|'); //使用了分組獲取 ////1.普通函式宣告 //function box(num1,num2) { // return num1 + num2; //} ////2.使用變數初始化函式 //var box = function (num1,num2) { // return num1 + num2; //} ////3.使用Function建構函式 //var box = new Function('num1', 'num2', 'return num1 + num2'); //PS:第三種方式我們不推薦,因為這種語法會導致解析兩次程式碼(第一次解析常規 //ECMAScript 程式碼,第二次是解析傳入建構函式中的字串),從而影響效能。但我們可以通 //過這種語法來理解"函式是物件,函式名是指標"的概念。 ////二.作為值的函式 //ECMAScript 中的函式名本身就是變數,所以函式也可以作為值來使用。也就是說,不 //僅可以像傳遞引數一樣把一個函式傳遞給另一個函式,而且可以將一個函式作為另一個函式 //的結果返回。 //function box(sumFunction,num) { // return sumFunction(num);//someFunction //} //function sum(num) { // return num *(num+1)/2; //} //var result = box(sum, 100);//傳遞函式到另一個函式裡 //alert(result); ////三.函式內部屬性 //在函式內部,有兩個特殊的物件:arguments 和this。arguments 是一個類陣列物件,包 //含著傳入函式中的所有引數,主要用途是儲存函式引數。但這個物件還有一個名叫callee 的 //屬性,該屬性是一個指標,指向擁有這個arguments 物件的函式。 //function box(num) { // if (num <= 1) { // return 1; // } else { // return num * box(num - 1); //一個簡單的的遞迴 // } //} ////對於階乘函式一般要用到遞迴演算法,所以函式內部一定會呼叫自身;如果函式名不改變 ////是沒有問題的,但一旦改變函式名,內部的自身呼叫需要逐一修改。為了解決這個問題,我 ////們可以使用arguments.callee 來代替。 //function box(num) { // if (num <= 1) { // return 1; // } else { // return num * arguments.callee(num-1);//使用callee 來執行自身 // } //} //函式內部另一個特殊物件是this,其行為與Java 和C#中的this 大致相似。換句話說, //this 引用的是函資料以執行操作的物件,或者說函式呼叫語句所處的那個作用域。PS:當在 //全域性作用域中呼叫函式時,this 物件引用的就是window。 //便於理解的改寫例子 //window.color = '紅色的'; //全域性的,或者var color = '紅色的';也行 //alert(this.color); //列印全域性的color //var box = { // color : '藍色的', //區域性的color // sayColor : function () { // alert(this.color); //此時的this 只能box 裡的color // } //}; //box.sayColor(); //列印區域性的color //alert(this.color); //還是全域性的 ////引用教材的原版例子 //window.color = '紅色的'; //或者var color = '紅色的';也行 //var box = { // color: '藍色的' //}; //function sayColor() { // alert(this.color); //這裡第一次在外面,第二次在box 裡面 //} //sayColor(); //box.sayColor = sayColor; //把函式複製到box 物件裡,成為了方法 //box.sayColor(); ////對於prototype 屬性,它是儲存所有例項方法的真正所在,也就是原型。這個屬性, ////我們將在面向物件一章詳細介紹。而prototype 下有兩個方法:apply()和call(),每個函式都 ////包含這兩個非繼承而來的方法。這兩個方法的用途都在特定的作用域中呼叫函式,實際上等 ////於設定函式體內this 物件的值。 //function box(num1,num2) { // return num1 + num2;//原函式 //} //function sayBox(num1,num2) { // return box.apply(this, [num1, num2]);//this表示作用域,這裡是window //} //[]表示box所需要的引數 //function sayBox2(num1,num2) { // return box.apply(this, arguments);//arguments物件表示box所需要的引數 //} //alert(sayBox(10, 10));//20 //alert(sayBox2(10, 10));//20 ////call()方法於apply()方法相同,他們的區別僅僅在於接收引數的方式不同。對於call()方 ////法而言,第一個引數是作用域,沒有變化,變化只是其餘的引數都是直接傳遞給函式的。 //function box(num1, num2) { // return num1 + num2; //} //function callBox(num1, num2) { // return box.call(this, num1, num2); //和apply 區別在於後面的傳參 //} //alert(callBox(10, 10));//20 ////事實上,傳遞引數並不是apply()和call()方法真正的用武之地;它們經常使用的地方是 ////能夠擴充套件函式賴以執行的作用域。 //var color = '紅色的'; //或者window.color = '紅色的';也行 //var box = { // color : '藍色的' //}; //function sayColor() { // alert(this.color); //} //sayColor(); //作用域在window //sayColor.call(this); //作用域在window //sayColor.call(window); //作用域在window //sayColor.call(box); //作用域在box,物件冒充 ////這個例子是之前作用域理解的例子修改而成,我們可以發現當我們使用call(box)方法的 ////時候,sayColor()方法的執行環境已經變成了box 物件裡了。 ////使用call()或者apply()來擴充作用域的最大好處,就是物件不需要與方法發生任何耦合 ////關係(耦合,就是互相關聯的意思,擴充套件和維護會發生連鎖反應)。也就是說,box 物件和 ////sayColor()方法之間不會有多餘的關聯操作,比如box.sayColor = sayColor; ////ECMAScript 中所有函式的引數都是按值傳遞的,言下之意就是說,引數不會按引用傳 ////遞,雖然變數有基本型別和引用型別之分。 //function box(num) { //按值傳遞,傳遞的引數是基本型別 // num += 10; //這裡的num 是區域性變數,全域性無效 // return num; //} //var num = 50; //var result = box(num); //alert(result); //60 //alert(num); //50 ////PS:以上的程式碼中,傳遞的引數是一個基本型別的值。而函式裡的num 是一個區域性變 ////量,和外面的num 沒有任何聯絡。 //下面給出一個引數作為引用型別的例子。 //function box(obj) { //按值傳遞,傳遞的引數是引用型別 // obj.name = 'Lee'; //} //var p = new Object(); //box(p); //alert(p.name); //PS:如果存在按引用傳遞的話,那麼函式裡的那個變數將會是全域性變數,在外部也可 //以訪問。比如PHP 中,必須在引數前面加上&符號表示按引用傳遞。而ECMAScript 沒有這 //些,只能是區域性變數。可以在PHP 中瞭解一下。 //PS:所以按引用傳遞和傳遞引用型別是兩個不同的概念。 //function box(obj) { // obj.name = 'Lee'; // var obj = new Object(); //函式內部又建立了一個物件 // obj.name = 'Mr.'; //並沒有替換掉原來的obj //} //var p = new Object(); //box(p); //alert(p.name); ////最後得出結論,ECMAScript 函式的引數都將是區域性變數,也就是說,沒有按引用傳遞。 ////雖然typeof 運算子在檢查基本資料型別的時候非常好用,但檢測引用型別的時候,它就 ////不是那麼好用了。通常,我們並不想知道它是不是物件,而是想知道它到底是什麼型別的對 ////象。因為陣列也是object,null 也是Object 等等。 ////這時我們應該採用instanceof 運算子來檢視。 //var box = [1,2,3]; //alert(box instanceof Array); //是否是陣列 //var box2 = {}; //alert(box2 instanceof Object); //是否是物件 //var box3 = /g/; //alert(box3 instanceof RegExp); //是否是正則表示式 //var box4 = new String('Lee'); //alert(box4 instanceof String); //是否是字串物件 ////PS:當使用instanceof 檢查基本型別的值時,它會返回false。 ////5.執行環境及作用域 ////執行環境是JavaScript 中最為重要的一個概念。執行環境定義了變數或函式有權訪問的 ////其他資料,決定了它們各自的行為。 ////全域性執行環境是最外圍的執行環境。在Web 瀏覽器中,全域性執行環境被認為是window ////物件。因此所有的全域性變數和函式都是作為window 物件的屬性和方法建立的。 //var box = 'blue'; //宣告一個全域性變數 //function setBox() { // alert(box); //全域性變數可以在函式裡訪問 //} //setBox(); //執行函式 ////全域性的變數和函式,都是window 物件的屬性和方法。 //var box = 'blue'; //function setBox() { // alert(window.box); //全域性變數即window 的屬性 //} //window.setBox(); //全域性函式即window 的方法 ////PS:當執行環境中的所有程式碼執行完畢後,該環境被銷燬,儲存在其中的所有變數和 ////函式定義也隨之銷燬。如果是全域性環境下,需要程式執行完畢,或者網頁被關閉才會銷燬。 ////PS:每個執行環境都有一個與之關聯的變數物件,就好比全域性的window 可以呼叫變數 ////和屬性一樣。區域性的環境也有一個類似window 的變數物件,環境中定義的所有變數和函式 ////都儲存在這個物件中。(我們無法訪問這個變數物件,但解析器會處理資料時後臺使用它) ////函式裡的區域性作用域裡的變數替換全域性變數,但作用域僅限在函式體內這個區域性環境。 //var box = 'blue'; //function setBox() { // var box = 'red'; //這裡是區域性變數,出來就不認識了 // alert(box); //} //setBox(); //alert(box); //red blue ////通過傳參,可以替換函式體內的區域性變數,但作用域僅限在函式體內這個區域性環境。 //var box = 'blue'; //function setBox(box) { //通過傳參,替換了全域性變數 // alert(box); //} //setBox('red'); //alert(box); ////函式體內還包含著函式,只有這個函式才可以訪問內一層的函式。 //var box = 'blue'; //function setBox() { // function setColor() { // var b = 'orange'; // alert(box); // alert(b); // } // setColor(); //setColor()的執行環境在setBox()內 //} //setBox(); ////PS:每個函式被呼叫時都會建立自己的執行環境。當執行到這個函式時,函式的環境 ////就會被推到環境棧中去執行,而執行後又在環境棧中彈出(退出),把控制權交給上一級的執 ////行環境。 ////PS:當代碼在一個環境中執行時,就會形成一種叫做作用域鏈的東西。它的用途是保 ////證對執行環境中有訪問許可權的變數和函式進行有序訪問。作用域鏈的前端,就是執行環境的 ////變數物件。 ////記憶體問題 ////JavaScript 具有自動垃圾收集機制,也就是說,執行環境會負責管理程式碼執行過程中使 ////用的記憶體。其他語言比如C 和C++,必須手工跟蹤記憶體使用情況,適時的釋放,否則會造 ////成很多問題。而JavaScript 則不需要這樣,它會自行管理記憶體分配及無用記憶體的回收。 ////JavaScript 最常用的垃圾收集方式是標記清除。垃圾收集器會在執行的時候給儲存在內 ////存中的變數加上標記。然後,它會去掉環境中正在使用變數的標記,而沒有被去掉標記的變 ////量將被視為準備刪除的變數。最後,垃圾收集器完成記憶體清理工作,銷燬那些帶標記的值並 ////回收他們所佔用的記憶體空間。 ////垃圾收集器是週期性執行的,這樣會導致整個程式的效能問題。比如IE7 以前的版本, ////它的垃圾收集器是根據記憶體分配量執行的,比如256 個變數就開始執行垃圾收集器,這樣, ////就不得不頻繁地執行,從而降低的效能。 ////一般來說,確保佔用最少的記憶體可以讓頁面獲得更好的效能。那麼優化記憶體的最佳方案, ////就是一旦資料不再有用,那麼將其設定為null 來釋放引用,這個做法叫做解除引用。這一 ////做法適用於大多數全域性變數和全域性物件。 //var o = { // name : 'Lee' //}; //o = null; //解除物件引用,等待垃圾收集器回收 //var box = document.getElementById('box'); //alert(box.children.length); ////關係掩碼錶 ////掩碼節點關係 ////1 無關(節點不存在) ////2 居前(節點在參考點之前) ////4 居後(節點在參考點之後) ////8 包含(節點是參考點的祖先) ////16 被包含(節點是參考點的後代) ////PS:為什麼會出現20,那是因為滿足了4 和16 兩項,最後相加了。為了能讓所有瀏覽 ////器都可以相容,我們必須寫一個相容性的函式。 ////傳遞參考節點(父節點),和其他節點(子節點) //function contains(refNode, otherNode) { // //判斷支援contains,並且非Safari 瀏覽器 // if (typeof refNode.contains != 'undefined' && // !(BrowserDetect.browser == 'Safari' && BrowserDetect.version < 3)) { // return refNode.contains(otherNode); // //判斷支援compareDocumentPosition 的瀏覽器,大於16 就是包含 // } else if (typeof refNode.compareDocumentPosition == 'function') { // return !!(refNode.compareDocumentPosition(otherNode) > 16); // } else { // //更低的瀏覽器相容,通過遞迴一個個獲取他的父節點是否存在 // var node = otherNode.parentNode; // do { // if (node === refNode) { // return true; // } else { // node = node.parentNode; // } // } while (node != null); // } // return false; //}