javascript
JavaScript知识点总结(二)
變量, 作用域, 垃圾收集(內(nèi)存問題)
基本類型和引用類型
ES中的變量包含基本類型值和引用類型值
基本類型值指的是簡單的數(shù)據(jù)段
引用類型值值那些可能有多個值構(gòu)成的對象
五種基本數(shù)據(jù)類型(Undefined, Null, Boolean, Number, String)的值即基本類型值是按值訪問的, 因此操作的是保存在變量中實際的值
引用類型值是保存在內(nèi)存中的對象,ES不允許直接訪問內(nèi)存中的位置, 即不能直接操作對象的內(nèi)存空間. 在操作對象時, 實際上是在操作對象的引用而不是實際的對象.
當(dāng)復(fù)制保存在對象中的某個變量時, 操作的是對象的引用. 但在為對象添加屬性時, 操作的是實際的對象.
動態(tài)的屬性
定義基本類型的值和引用類型的值方式是基本一樣的, 就是創(chuàng)建一個變量, 然后為該變量賦值.
創(chuàng)建變量以后,基本類型的值和引用類型的值執(zhí)行的操作有很大不同.
//引用類型可以為其添加或刪除屬性和方法 var p = new Object(); p.name = "Jon"; console.log(p.name); //Jon delete p.name; console.log(p.name); //undefined //基本類型不能添加屬性, 因為即使添加了也不能訪問 var n = "Jon"; //一個string字符串類型 n.age = 25; console.log(n.age); //undefined復(fù)制變量值
復(fù)制基本類型值的變量值與復(fù)制引用類型值的變量值也存在不同.
復(fù)制基本類型值時, 是直接創(chuàng)建新值, 占據(jù)不同的內(nèi)存(棧)空間, 復(fù)制之后兩個變量可以參與任何操作而不互相影響
var n1 = 5; var n2 = n1; //復(fù)制n1復(fù)制引用類型值時, 同樣也會把儲存在變量對象中的值復(fù)制一份到新變量分配的空間中, 但這個新變量的值其實是一個指針, 指向儲存在堆中的一個對象. 所以兩者引用的是同一個對象. 所以, 改變其中一個變量, 另一個變量也會受到影響.
var o1 = new Object(); var o2 = o1; o1.name = 'Jon'; console.log(o2.name); //o1和o2指向的是堆內(nèi)存中的同一個對象, 所以同樣會輸出Jon參數(shù)傳遞
ES中所有函數(shù)的參數(shù)都是按值傳遞的,不存在引用傳遞的參數(shù)
函數(shù)外部的值復(fù)制給函數(shù)內(nèi)部的參數(shù), 就等于把值從一個變量復(fù)制到另一個變量一樣.
基本類型值的傳遞就像基本類型變量的復(fù)制一樣, 向參數(shù)傳遞基本類型值的時候,被傳遞的值會被復(fù)制給一個局部變量(即命名參數(shù), 用ES的概念來說, 就是arguments中的一個元素)
引用類型值的傳遞就像引用類型變量的復(fù)制一樣, 向參數(shù)傳遞引用類型值的時候, 會把這個值在內(nèi)存中的地址復(fù)制給一個變量, 因此這個局部變量的變化會反映在函數(shù)的外部
function addTen(n){ //參數(shù)(這里是n)其實是函數(shù)的局部變量n += 10;return n; } var c = 20; var r = addTen(c); //調(diào)用時,c作為一個局部變量傳遞給n,函數(shù)體內(nèi)又會自増10然后返回 console.log(c); //外部的c變量不會被影響,還是20 console.log(r); //30 function setName(obj){obj.name = "Jon"; } var p = new Object(); //創(chuàng)建了一個對象并保存在變量p中 setName(p); //隨即被傳遞到setName()中,p復(fù)制給了obj console.log(p.name); //所以obj的屬性name也能被p訪問到,所以這里輸出Jon //證明對象是按值傳遞的例子 function setName(obj){obj.name = 'Jon';obj = new Object(); //為obj重新定義了一個對象obj.name = 'Percy'; //然后為obj定義了另一個name屬性 }//如果p是引用傳遞的話, 那么p就會自動被修改為指向其name屬性值為Percy的對象,但下面的例子輸出的仍然是Jon. 說明即使函數(shù)內(nèi)部修改了參數(shù)的值, 但原始的引用仍然保持不變. var p = new Object(); setName(p); console.log(p.name); //Jon可以吧ES函數(shù)的參數(shù)想象成局部變量.
檢測類型
typeof — 檢測變量是哪種基本數(shù)據(jù)類型.string, number, boolean, undefined, object(如果變量的值是一個對象或null, 則返回object)
console.log(typeof "Jon"); //string console.log(typeof true); //boolean console.log(typeof 1); //number var a; console.log(typeof a); //undefined console.log(typeof null); //object var o = new Object(); console.log(typeof o); //objectinstanceof — 檢測引用數(shù)據(jù)類型值時, 檢測其引用數(shù)據(jù)類型值是什么類型的對象
result = variable instanceof constructor如果變量是給定引用類型的實例, 那么instanceof操作符就會返回true
console.log(person instanceof Object); //變量person是Object嗎? console.log(colors instanceof Array); //變量colors是Array嗎? console.log(pattern instanceof RegExp); //變量pattern是RegExp嗎?所有引用類型的值都是Object的實例, 所以檢測一個引用類型的值和Object構(gòu)造函數(shù)時會始終返回true
使用instanceof操作符檢測基本類型的值會始終返回false, 因為基本類型不是對象
執(zhí)行環(huán)境, 作用域
執(zhí)行環(huán)境定義了變量或函數(shù)是否有權(quán)訪問的其他數(shù)據(jù).
全局執(zhí)行環(huán)境是最外圍的執(zhí)行環(huán)境(Web瀏覽器中指的是window對象),因此所以全局變量和函數(shù)都是作為window對象的屬性和方法創(chuàng)建的.
每個函數(shù)都有自己的執(zhí)行環(huán)境, 當(dāng)執(zhí)行流進入一個函數(shù)時, 函數(shù)的環(huán)境就會被推入一個環(huán)境棧中, 函數(shù)執(zhí)行之后, 棧將其環(huán)境彈出, 把控制權(quán)返回給之前的執(zhí)行環(huán)境.
代碼在一個環(huán)境中執(zhí)行時, 會創(chuàng)建變量對象的一個作用域鏈, 它保證了對執(zhí)行環(huán)境有權(quán)訪問的所有變量和函數(shù)的有序訪問.
全局執(zhí)行環(huán)境的變量對象始終都是作用域鏈中的最后一個對象
沒有塊級作用域
if(true){var color = "blue"; } console.log(color); //ES中, 在外部依然能訪問塊級作用域內(nèi)的變量和函數(shù) for (var i=0; i < 10; i++){doSomething(i); } alert(i); //可以訪問塊級作用域內(nèi)的變量,輸出10 //ES中查詢標(biāo)識符會從正在執(zhí)行的局部環(huán)境查找, 如果當(dāng)前局部環(huán)境查找不到, 就會沿著作用域鏈一級一級向上查找. 如果在全局環(huán)境都找不到需要查找的標(biāo)識符, 說明該變量未聲明 var color = "blue"; function getColor(){return color; } console.log(getColor()); //這里會先搜索getColor()內(nèi)部有沒有color變量, 如果沒有就向上一級查找, 直到查找到位置, 這里在上一級已經(jīng)找到, 所以會輸出blue var color = "blue"; function getColor(){var color = "red";return color; } console.log(getColor()); //red , 同級找到就不會再向上查找垃圾收集
標(biāo)記清除
ES中, 當(dāng)變量進入環(huán)境(例如, 在函數(shù)中聲明一個變量時), 就把這個變量標(biāo)記為"進入環(huán)境", 這種進入環(huán)境的變量從邏輯上講不能釋放其內(nèi)存, 因為有可能用到它們. 而當(dāng)變量離開環(huán)境時, 就將其標(biāo)記為"離開環(huán)境".
過程 :
垃圾收集器運行的時候會給儲存在內(nèi)存中的所有變量都加上標(biāo)記(可以使用任意可使用的標(biāo)記方式)
接著會去掉環(huán)境中的變量, 以及被環(huán)境中的變量引用的變量的標(biāo)記(個人理解就是當(dāng)前執(zhí)行環(huán)境的變量以及被環(huán)境中變量引用的變量 的標(biāo)記)
在此之后再被加上標(biāo)記的變量, 就是被視為準(zhǔn)備刪除的變量(因為它們之前用的時候已經(jīng)被標(biāo)記一次了, 再次(第二次)標(biāo)記說明已經(jīng)使用完畢), 環(huán)境中的變量已經(jīng)無法訪問這些變量了
垃圾收集器完成內(nèi)存清除工作, 銷毀那些帶標(biāo)記的值并回收它們所占用的內(nèi)存空間
引用計數(shù)
引用計數(shù)的含義是跟蹤記錄每個值被引用的次數(shù)
聲明了一個變量并將一個引用類型值賦值給該變量時, 則這個值的引用次數(shù)就是1
該引用類型值又賦值給另一個變量, 則引用次數(shù)加1
相反, 如果包含對這個值的引用的變量(如a變量)又取得了另一個引用類型值, 則前一個引用類型值的引用次數(shù)減1
當(dāng)這個引用類型值的引用次數(shù)變成0時, 則說明沒辦法再訪問這個值了, 因而可以將其回收, 釋放內(nèi)存空間
該垃圾收集機制早期的循環(huán)引用問題
function problem(){var oA = new Object();var oB = new Object();//oA與oB通過各自的屬性互相引用, 在標(biāo)記清除的回收機制中, 它們的引用次數(shù)永遠不可能是0, 并且如果這個函數(shù)重復(fù)多次調(diào)用, 會導(dǎo)致大量內(nèi)存得不到回收//所以這種方式已經(jīng)被摒棄, 而采用標(biāo)記清除來實現(xiàn)其垃圾回收oA.someOtherObject = oB;oB.anotherObject = oA; }IE中的BOM與DOM使用引用計數(shù)來作為垃圾收集機制的問題
var element = document.getElementById("some_element"); var myObject = new Object(); //DOM元素(element)與一個原生JS對象(myObject)之間創(chuàng)建了循環(huán)引用 myObject.element = element; //myObject的element屬性指向element對象 element.someObject = myObject; //變量element也有一個屬性名叫someObject回指myObject //基于上述問題, 即使將力爭中的DOM從頁面中移除, 它也永遠不會被回收//解決方案是在他們不使用時手動斷開原生JS對象與DOM元素之間的鏈接 //把變量設(shè)置為null意味著斷開變量與它之前引用的值之間的鏈接, 當(dāng)下一次的垃圾回收執(zhí)行時, 就會刪除這些值并回收他它們占用的內(nèi)存 myObject.element = null; element.someObject = null; //IE9以上已經(jīng)把DOM和BOM轉(zhuǎn)換成了真正的JavaScript對象, 所以避免了上述問題性能問題及內(nèi)存管理
性能問題
早期的瀏覽器按內(nèi)存分配量運行的, 達到一個臨界值就會觸發(fā)垃圾回收機制, 這個問題在于, 如果一個腳本中包含大量的變量, 那么會在其生命周期也保持有那么多變量, 導(dǎo)致長時間處于垃圾回收機制的臨界值, 從而使垃圾回收機制頻繁運行, 造成嚴(yán)重的性能問題.
新版本的瀏覽器已經(jīng)將其垃圾回收機制的工作方式改變, 會動態(tài)的調(diào)整觸發(fā)的臨界值.
內(nèi)存管理
優(yōu)化內(nèi)存占用的方式, 就是為執(zhí)行中的代碼只保存必要的數(shù)據(jù). 一旦數(shù)據(jù)不再有用, 就通過將其值設(shè)置為null來釋放引用 — 即解除引用
function createPerson(){var localPerson = new Object();localPerson.name = name;return localPerson; } var globalPerson = createPerson("Jon");//手動解除globalPerson的引用 globalPerson = null;引用類型
引用類型的值(對象)是引用類型的一個實例.
ES中, 引用類型是一種數(shù)據(jù)結(jié)構(gòu), 用于將數(shù)據(jù)和功能組織在一起.就像傳統(tǒng)的類一樣.
對象是某個特定引用類型的實例
新對象使用new操作符后跟一個構(gòu)造函數(shù)來創(chuàng)建的.
構(gòu)造函數(shù)本身就是一個函數(shù), 只不過該函數(shù)是出于創(chuàng)建新對象的目的而定義的.
var person = new Object(); //創(chuàng)建Object引用類型的一個新實例, 并把實例保存在person變量中, 并為新對象定義了默認(rèn)的屬性和方法ES中提供了很多原生引用類型,用于日常的開發(fā)任務(wù).
Object類型
//創(chuàng)建Object實例 var person = new Object(); person.name = "Jon"; person.age = 25; person.sayName = function(){console.log("My name is " + name); }//使用 對象字面量 創(chuàng)建 var person = {name : "Jon",age : 25,sayName : function(){console.log("My name is " + name);} };//使用 對象字面量 時, 屬性名也能使用字符串 var person2 = {"name" : "Mark","age" : 24,//... } var person = {name : "Jon",age : 25,sayName : function(){console.log("My name is " + name);} };//訪問對象屬性: 使用點表示法或者方括號表示法 console.log(person.name); //常用, Jon console.log(person[name]); //不常用, 但如果屬性名包含特殊字符或者空格等, 可以使用方括號表示法來訪問對象屬性Array類型
ES的Array每一項都可以保存任何類型的數(shù)據(jù).
ES的Array大小是可以動態(tài)調(diào)整的, 即可以隨著數(shù)據(jù)的添加自動增長以容納新增數(shù)據(jù).
數(shù)組的創(chuàng)建方式
var arr1 = new Array(); //創(chuàng)建數(shù)據(jù)的基本方式 var arr2 = new Array(10); //預(yù)先知道要保存的項目數(shù)量可以直接創(chuàng)建特定長度的數(shù)組, 這里創(chuàng)建了length為10的數(shù)組 var arr3 = new Array("Jon","Mark","Martin"); //創(chuàng)建包含特定值的數(shù)組 var arr4 = Array(5); //創(chuàng)建數(shù)組也可以省略new操作符 var arr5 = ["blue","yellow","green"]; //使用數(shù)組字面量 表示法來創(chuàng)建數(shù)組, 使用這種方法并不會調(diào)用Array構(gòu)造函數(shù)數(shù)組的讀取和設(shè)置
var arr1 = ["blue","yellow","green"];//讀取 console.log(arr1[0]); //數(shù)組元素索引從0開始, 訪問每個元素就是 數(shù)組名[索引號], 比如第1個就是arr1[0] , 所以這里會輸出blue//設(shè)置 arr1[1] = "red"; //把數(shù)組arr1的第二個元素值設(shè)置為red; console.log(arr[1]); //red arr1[arr1.length] = "black"; //在數(shù)組的末尾添加一個元素 console.log(arr1); //["blue", "red", "green", "black"]//訪問數(shù)組長度 console.log(arr1.length); //3 //數(shù)組長度屬性length屬性不是只讀的..可以通過設(shè)置其長度來改變數(shù)組的長度 arr1.length = 5; console.log(arr1.length); //5 console.log(arr1[4]); //undefined//喪心病狂地增加數(shù)組長度 arr1[99] = "purple"; //除了前面有效的值和這個新增有效的值, 其他的都是undefined console.log(arr1.length); //100檢測對象是否為數(shù)組 — instanceof 或者 ES5里面新增的Array.isArray()
var arr = []; if(Array.isArray(arr)){//do sth... }轉(zhuǎn)換方法
var arr = [1,2,3]; console.log(arr.toString()); //1,2,3(返回的是字符串形式拼接而成的用逗號分隔的字符串) console.log(arr.valueOf()); //1,2,3(返回的是原來的數(shù)組) console.log(arr); //1,2,3(與toString()一樣)//**使用join()方法可以使用不同的分隔符構(gòu)建指定的數(shù)組** console.log(arr.join("-")); //1-2-3//如果數(shù)組中的值是null或undefined, 那么該值在join(),toLocaleString(),toString(),valueOf()中返回的結(jié)果會以空字符串表示數(shù)組的插入和刪除
棧方法
LIFO(Last-In-First-Out), 后進先出
push(), 接收任意參數(shù)并把它們逐個添加到數(shù)組末尾, 返回修改后數(shù)組的長度
pop(), 從數(shù)組末尾移除最后一項, 減少數(shù)組的length值, 然后返回移除的項
var colors = Array(); var count = colors.push("red","green"); //推入兩項 console.log(count); //2count = colors.push("black"); //推入另一項 console.log(count); //3var item = colors.pop(); //取得最后一項 console.log(item); //black console.log(colors.length); //2 //可以跟其他數(shù)組方法一起使用var colors = ["red","blue"];colors.push("brown"); //添加一項colors[3] = "purple"; //添加一項console.log(colors.length); //4var item = colors.pop(); //取得一項console.log(item); //purple隊列方法
FIFO(First-In-First-Out), 先進先出
數(shù)組最左側(cè)的會被移除, 最右側(cè)的會被添加
shift(), 移除數(shù)組中的第一個項(左邊)并返回該項, 同時將數(shù)組長度減1
unshift(),在數(shù)組前端(左邊)添加任意個項并返回數(shù)組長度
//結(jié)合使用shift()和push()方法, 可以像使用隊列一樣使用數(shù)組 var colors = []; var count = colors.push("red","green"); //推入兩項 console.log(count); //2count = colors.push("black"); //推入另一項 console.log(count); //3var item = colors.shift(); //取得第一項(左邊) console.log(item); //red console.log(colors.length); //2 //結(jié)合使用unshift()和pop()方法, 可以反向模擬隊列, 即在數(shù)組的前端(左邊)添加項, 在末尾(右邊)移除項 var colors = []; var count = colors.unshift("red","green"); //推入兩項 count = colors.unshift("black"); //推入另一項 console.log(count); //3var item = colors.pop(); //取得最后一項 console.log(item); //black console.log(colors.length); //2重排序方法
reverse(),反向排序
sort(),把數(shù)組的每一項轉(zhuǎn)換成字符串再進行排序
//reverse() var values = [1, 2, 3, 4, 5]; values.reverse(); console.log(values); //5, 4, 3, 2, 1 //sort()方法因為會轉(zhuǎn)換為字符串, 所以排序時會出現(xiàn)問題, 很多時候不會按照正常的規(guī)則排列 -- 即最小的排最前面, 最大的排最后面 //所以使用sort()時應(yīng)該接收一個比較函數(shù), 比較函數(shù)定義兩個參數(shù), 如果第一個參數(shù)應(yīng)該位于第二個之前就返回一個負(fù)數(shù), 如果兩個參數(shù)相等就返回0, 如果第一個參數(shù)應(yīng)該位于第二個之后就返回一個整數(shù). function compare(value1, value2){if(value1 < value2){return -1;}else if(value1 > value2){return 1;}else{return 0;} } //使用上面的比較函數(shù) var values = [3, 2, 6, 8, 1]; values.sort(compare); console.log(values); //1, 2, 3, 6, 8操作方法
concat(), 拼接接收的參數(shù), 返回一個拼接后的數(shù)組.
slice(), 數(shù)組截取方法, 接受一個或兩個索引參數(shù), 一個時, 會返回該索引到數(shù)組結(jié)尾的項(包括該索引的項), 兩個時, 會返回第一個到第二個索引參數(shù)之間的項(不包括第二個索引的項).
splice(), 像數(shù)組的中部插入項, 有3種方式
刪除 : 兩個參數(shù), 要刪除的起始索引位置, 以及要刪除的項
插入 : 三個參數(shù), 起始索引位置, 要刪除的項數(shù), 要插入的項. 如果第二個參數(shù)設(shè)置為0, 則不刪除直接插入
替換 : 三個參數(shù), 起始所以位置, 要刪除的項數(shù), 要插入的想, 跟上面插入一樣, 只不過第二個參數(shù)不為0, 刪除后插入第三個參數(shù)的數(shù)據(jù)
位置方法
indexOf(),兩個參數(shù), 要查找的項, 以及(可選的)查找的起點位置的索引
lastIndexOf(),同上, 但該方法會在數(shù)組的末尾向前查找
兩個方法都會返回要查找的想在數(shù)組中的位置, 沒有找到的話返回-1
var numbers = [1,2,3,4,5,4,3,2,1];alert(numbers.indexOf(4));//3 alert(numbers.lastIndexOf(4)); //是從左邊開始數(shù)起的索引值, 但尋找是從右邊向左找, 所以是5alert(numbers.indexOf(4, 4)); //5 alert(numbers.lastIndexOf(4, 4)); //3 var person = { name: "Nicholas" }; var people = [{ name: "Nicholas" }]; var morePeople = [person];alert(people.indexOf(person)); //-1 alert(morePeople.indexOf(person)); //0迭代方法
ES5定義了5個迭代方法, 每個方法都接收兩個參數(shù), 一是要在每一項上運行的函數(shù), 二(可選)是運行在該函數(shù)的作用域?qū)ο?— 影響this的值.
傳入這5個迭代方法作為參數(shù)的函數(shù)(即第一個參數(shù))會接收三個參數(shù), 數(shù)組項的值, 該項在數(shù)組中的位置 以及 數(shù)組對象本身.
every(), 對數(shù)組的每一項運行給定函數(shù), 如果該函數(shù)對每一項都返回true, 則返回true
filter(), 對數(shù)組的每一項運行給定函數(shù), 返回該函數(shù)會返回true的項組成的數(shù)組
forEach(), 對數(shù)組的每一項運行給定函數(shù), 沒有返回值
map(), 對數(shù)組的每一項運行給定函數(shù), 返回每次函數(shù)調(diào)用的結(jié)果組成的數(shù)組
some(), 對數(shù)組的每一項運行給定函數(shù), 如果該函數(shù)對任一項返回true, 則返回true
歸并方法
ES5新增reduce()和reduceRight()兩個歸并方法, 均會迭代數(shù)組的所有項, 然后構(gòu)建一個最終返回的值. 前者會在數(shù)組的第一項開始迭代, 后者相反.
兩個方法都接收兩個參數(shù), 一是在每一項上調(diào)用的函數(shù), 二是(可選)作為歸并基礎(chǔ)的初始值
其中在每一項上調(diào)用的函數(shù)接收四個參數(shù), 前一個值, 當(dāng)前值, 項的索引, 數(shù)組對象
//reduce() var values = [1, 2, 3, 4, 5]; var sum = values.reduce(function(prev, cur, index, array){//第一次執(zhí)行回調(diào)函數(shù)時, prev是1, cur是2//第二次, prev是3(1加2的結(jié)果), cur是3(數(shù)組第三項)return prev + cur; }); console.log(sum); //15 //reduceRight() var values = [1, 2, 3, 4, 5]; var sum = values.reduce(function(prev, cur, index, array){//左右相似, 不過作用方向相反//第一次執(zhí)行回調(diào)函數(shù)時, prev是5, cur是4return prev + cur; }); console.log(sum); //15Date類型
var now = new Date(); //創(chuàng)建日期對象, 獲得當(dāng)前時間其他參見 :
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Date#.E6.91.98.E8.A6.81
RegExp類型
//創(chuàng)建正則表達式 var expression = / pattern / flags ;模式(pattern)部分可以是任何簡單或復(fù)雜的表達式, 包括字符類, 限定符, 分組, 向前查找, 反向引用
標(biāo)志(flags)可以有一或多個, 用以表明正則表達式的行為 :
g , 全局(global)模式, 即模式會被應(yīng)用于所有字符串, 而非在發(fā)現(xiàn)第一個匹配項時立即停止
i , 不區(qū)分大小寫(case-insensitive)模式, 即在確定匹配項時忽略模式與字符串的大小寫
m , 多行(multiline)模式, 即在到達一行文本末尾時還會繼續(xù)查找下一行中是否存在與模式匹配的項
正則表達式中的元字符包括 : ( [ { \ ^ $ | ) ? * + .]}
如果需要在正則表達式中使用這些元字符, 則必須進行轉(zhuǎn)義 :
/**匹配第一個"bat"或"cat", 不區(qū)分大小寫*/var pattern1 = /[bc]at/i;/**匹配第一個" [bc]at", 不區(qū)分大小寫*/var pattern2 = /\[bc\]at/i;/**匹配所有以"at"結(jié)尾的三個字符的組合, 不區(qū)分大小寫*/var pattern3 = /.at/gi;/**匹配所有以".at"結(jié)尾的三個字符的組合, 不區(qū)分大小寫*/var pattern4 = /\.at/gi; //不使用上面的字面量形式來定義正則表達式, 而使用RegExp構(gòu)造函數(shù), //接收兩個參數(shù), 一是要匹配的字符串模式, 二(可選)是標(biāo)志字符串 /**匹配第一個"bat"或"cat", 不區(qū)分大小寫*/var pattern1 = /[bc]at/i; var pattern2 = new RegExp("[bc]at", "i");使用構(gòu)造函數(shù)模式時注意某些字符的雙重轉(zhuǎn)義問題 :
var pattern1 = /\[bc\]at/; var pattern1c = new RegExp("\\[bc\\]at"); //上面的構(gòu)造函數(shù)形式, 注意符號的雙重轉(zhuǎn)義var pattern2 = /\.at/; var pattern2c = new RegExp("\\.at");var pattern3 = /name\/age/; var pattern3c = new RegExp("name\\/age");var pattern4 = /\d.\d{1,2}/; var pattern4c = new RegExp("\\d.\\d{1,2}");var pattern5 = /\w\\hello\\123/; var pattern5c = new RegExp("\\w\\\\hello\\\\123");RegExp實例方法
exec(), RegExp對象的主要方法, 專門為捕獲組而設(shè)計的, 接收一個參數(shù), 即要應(yīng)用模式的字符串, 然后返回包含第一個匹配項信息的數(shù)組, 沒有匹配項的情況下返回null.
返回的數(shù)組是Array的實例, 但包含兩個額外的屬性,index和input, index表示匹配項在字符串中的位置, input表示應(yīng)用正則表達式的字符串.
….TODO
Function類型
函數(shù).每個函數(shù)都是Function類型的實例.
函數(shù)是對象, 函數(shù)名是一個指向函數(shù)對象的指針,不會與某個函數(shù)綁定
//函數(shù)定義 function sum(n1,n2){return n1 + n2; }//另一種方式 var sum = function(n1, n2){return n1 + n2; }//函數(shù)名只是指針, 所以一個函數(shù)能有多個名字 var anotherSum = sum; console.log(auntherSum(1+2)); //3 sum = null; //把sum設(shè)置為空 console.log(auntherSum(1+2)); //并不影響, 并且依然能輸出3ES中沒有重載
function addSomeNumber(n){return n + 100; }//后聲明的才有效 function addSomeNumber(n){return n + 200; }var r = addSomeNumber(100); //300//其實就相當(dāng)于下面的代碼 var addSomeNumber = function(n){return n + 100; }//覆蓋了前面的同名函數(shù) addSomeNumber = function(n){return n + 200; }var r = addSomeNumber(100); //300 //函數(shù)聲明與函數(shù)表達式的區(qū)別, 函數(shù)聲明支持函數(shù)聲明提升, 即解析器會率先解讀函數(shù)聲明, 然后才執(zhí)行代碼 alert(sum(10, 10)); //有效, 輸出20 function sum(n1, n2){return n1 + n2; }//但函數(shù)表達式不支持函數(shù)聲明提升 alert(sum(10, 10)); //錯誤 var sum = function(n1, n2){return n1 + n2; }函數(shù)名本身就是變量, 所以也能作為值來使用
function callSomeFunction(someFunction, someArgument){//第一個參數(shù)是函數(shù), 第二個參數(shù)是傳遞給該函數(shù)的一個值return someFunction(someArgument); }function add10(n){return n + 10; }//注意add10沒有加括號, 是因為只訪問函數(shù)的指針而不執(zhí)行函數(shù), 就要去掉括號 var r1 = callSomeFunction(add10, 10); console.log(r1); //20function getGreeting(name){return "Hi, " + name; }var r2 = callSomeFunction(getGreeting, "Jon"); console.log(r2); //Hi, Jon //從一個函數(shù)中返回另一個函數(shù) function createComparisonFunction(propertyName){return function(o1, o2){var v1 = o1[propertyName];var v2 = o2[propertyName];if(v1 < v2){return -1;}else if(v1 > v2){return 1;}else{return 0;}} }var data = [{name : "Jon", age : 25},{name : "Mark", age : 24} ];data.sort(createComparisonFunction("name")); console.log(data[0].name); //Jondata.sort(createComparisonFunction("age")); console.log(data[0].name); //Mark函數(shù)的內(nèi)部屬性
arguments的callee屬性, 是一個指針, 指向擁有這個arguments對象的函數(shù)
//階乘函數(shù) function factorial(n){if(n <= 1){return 1;}else{//函數(shù)執(zhí)行與函數(shù)名factorial緊緊耦合return n * factorial(n - 1);} }//使用callee消除耦合 function factorial(n){if(n <= 1){return 1;}else{return n * arguments.callee(n - 1);} }//trueFactorial獲得了factorial的值, 實際上是在另一個位置保存了一個函數(shù)的指針 var trueFactorial = factorial;//把factorial變成返回0的簡單函數(shù) factorial = function(){return 0; };//假如不使用arguments.callee, 那么下面的trueFactorial也會返回0, 使用了arguments.callee, 即可以解除耦合, 返回正常 console.log(trueFactorial(5)); //120 console.log(factorial(5)); //0this
window.color = "red"; var o = {color : "blue" };function sayColor(){console.log(this.color); }//在全局作用域內(nèi)調(diào)用, 此時this引用的對象是window, 所以輸出red sayColor(); //red//把函數(shù)賦給對象o并調(diào)用sayColor(), 此時this引用的對象是對象o, 所以輸出blue o.sayColor = sayColor; o.sayColor(); //blueES5新增的對象屬性caller, 這個屬性保存著調(diào)用當(dāng)前函數(shù)的函數(shù)的引用.
全局作用域調(diào)用時它的值為null
function outer(){inner(); }function inner(){console.log(inner.caller); }outer(); /*function outer(){inner();}*/ //更松散的耦合, 使用arguments.callee.caller function outer(){inner(); }function inner(){console.log(arguments.callee.caller); }outer(); /*function outer(){inner();}*/ //嚴(yán)格模式下, 訪問arguments.callee會導(dǎo)致錯誤; 訪問arguments.caller也會導(dǎo)致錯誤; 嚴(yán)格模式下還不能為函數(shù)的caller屬性賦值, 否則會導(dǎo)致錯誤函數(shù)屬性和方法
每個函數(shù)開始都包含兩個屬性, length,prototype
length, 表示函數(shù)希望接收的命名參數(shù)的個數(shù)
//length function sayName(name){console.log(name); }function sum(sum1, sum2){return num1 + num2; }function sayHi(){console.log("Hi"); }console.log(sayName.length); //1 console.log(sum.length); //2 console.log(sayHi.length); //0prototype, ES引用類型中保存所有實例方法的屬性, 該屬性不可枚舉
apply(), call(), ES函數(shù)中兩個原生的方法, 用途都是在特定的作用域中調(diào)用函數(shù), 實際上等于設(shè)置函數(shù)體內(nèi)this對象的值. 接收兩個參數(shù), 一是在其中運行函數(shù)的作用域, 二是參數(shù)數(shù)組(第二個參數(shù)可以是Array的實例, 也能是arguments對象)
//apply() function sum(num1, num2){return num1 + num2; }function callSum1(num1, num2){return sum.apply(this, arguments); //傳入arguments對象 }function callSum2(num1, num2){return sum.apply(this, [num1, num2]); //傳入數(shù)組 }console.log(callSum1(10, 10)); //20 console.log(callSum2(10, 10)); //20 //call()與apply()作用相同, 只是接收參數(shù)的方式不同, 使用call()時, 傳遞給函數(shù)的參數(shù)必須逐個列舉出來 function sum(num1, num2){return num1 + num2; }function callSum(num1, num2){return sum.call(this, num1, num2); }console.log(callSum(10, 10)); //20 //apply()和call()重要的作用是擴充函數(shù)的作用域, 好處是對象不需要和方法有任何的耦合關(guān)系 window.color = "red"; var o = {color : "blue" }function sayColor(){cosnole.log(this.color); }sayColor(); //redsayColor.call(this); //red sayColor.call(window); //red sayColor.call(o); //blueES5新增了bind()方法, 會創(chuàng)建一個函數(shù)的實例, 其this值會被綁定到傳給bind()函數(shù)的值
window.color = "red"; var o = {color : "blue" }function sayColor(){cosnole.log(this.color); }//用sayColor()方法綁定o對象, this的值指向o, 所以輸出blue var objectSayColor = sayColor.bind(o); objectSayColor(); //blue基本包裝類型
3種特殊的引用類型, Boolean, Number, String
這三種特殊的類型可以使用new操作符創(chuàng)建實例, 但如非必要不推薦
//Boolean var booleanObject = new Boolean(true); //不推薦使用 //Number var numberObject = new Number(10);//toFixed()按照指定的小數(shù)位返回數(shù)值的字符串表示 var num = 12; console.log(num.toFixed(2)); //12.00//toExponential()返回指數(shù)表示法(e表示法)表示的數(shù)值的字符串形式 var num2 = 11; console.log(num2.toExponential(1)); //1.1e1//toPrecision(), 返回合適的格式, 有可能是固定大小(fixed)格式, 也可能是e表示法, 接受一個參數(shù), 即表示數(shù)值的所有數(shù)字的位數(shù)(不包括指數(shù)部分)var num3 = 88; console.log(num3.toPrecision(1)); //9e+1 console.log(num3.toPrecision(2)); //99 console.log(num3.toPrecision(3)); //99.0 //String var stringObject = new String("Hi Jon");//length屬性, 表示字符串中包含的字符數(shù)量 console.log(stringObjet.length); //6//charAt與charCodeAt(), 一個參數(shù), 即需要查找的字符的索引, 返回查找到的字符, 后者得到的是 字符編碼 var s1 = "Happy FrontEnd!"; console.log(s1.charAt("F")); //6 console.log(s1.charCodeAt("F")); //72 //ES5可以使用方括號表示法, 接收一個索引值以返回得到的字符串 console.log(s1[3]); //p//字符串操作方法 //concat(), 用于拼接字符串 var s2 = "Hi "; var s3 = "Jon"; var r = s2.concat(s3); console.log(r); //Hi Jon //可以直接接受字符串使用 console.log("Hi", "Mark", "!"); //Hi Mark !//slice(), substr(), substring(), 用于截取字符串并返回一個副本 //slice()和substring()接收兩個參數(shù), 開始索引值和結(jié)束索引值, 返回兩個索引值之間的值, 在參數(shù)不是負(fù)數(shù)的時候作用相同 //substr(), 第一個參數(shù)接收開始的索引值, 第二個參數(shù)接收**返回的字符個數(shù)** //如果這三個方法不接收第二個參數(shù), 則返回開始字符串到結(jié)尾的字符串var s4 = "Have a Good Day!"; console.log(s4.slice(3)); //e a Good Day! console.log(s4.substring(3)); //e a Good Day! console.log(s4.substr(3)); //e a Good Day! console.log(s4.slice(3,8)); //e a G console.log(s4.substring(3,8)); //e a G console.log(s4.substr(3,8)); //e a Good//傳入負(fù)值的情況下, slice()會把 傳入的負(fù)值 和 字符串的長度相加; substr()會把第一個負(fù)值的參數(shù)加上字符串的長度, 而把第二個負(fù)的參數(shù)轉(zhuǎn)為0; substring()會把所有負(fù)值參數(shù)都轉(zhuǎn)為0 var s5 = "My WOW player is Warlock"; console.log(s5.slice(-3)); //-3 + 24(字符串長度) = 21(從索引值為21的字符開始); 輸出ock console.log(s5.substr(-3)); //-3 + 24(字符串長度) = 21(從索引值為21的字符開始); //輸出ock console.log(s5.substring(-3)); //所有負(fù)數(shù)參數(shù)轉(zhuǎn)換為0, 輸出My WOW player is Warlock console.log(s5.slice(3, -3)); //WOW player is Warl console.log(s5.substr(3, -3)); //輸出"", 因為第二個參數(shù)轉(zhuǎn)為0(返回字符的個數(shù)) console.log(s5.substring(3, -3)); //My//字符串位置方法, indexOf(), lastIndexOf(), 從一個字符串中搜索給定的子字符串, 然后返回字符串的位置(沒有則返回-1), 其中indexOf()會從頭開始搜索, 而lastIndexOf()會在后面開始搜索var s6 = "Happy WOW game!"; console.log(s6.indexOf("a")); //1 從前面開始搜索, 最先出現(xiàn)的索引位置是1 console.log(s6.lastIndexOf("a")); //11 從后面開始搜索, 最先出現(xiàn)的索引位置是11 //可以接收第二個可選參數(shù), 表示從字符串中的哪一個位置開始搜索 console.log(s6.lastIndexOf("a",4)); //11, 從索引值4的位置開始搜索, 索引值1的a已經(jīng)被忽略, 所以找到第二個a在索引值11的位置 console.log(s6.lastIndexOf("a",6)); //1, 從索引值6開始向前搜索, 所以位置11的a已經(jīng)被忽略, 所以找到第二個a, 在索引值1的位置 //indexOf()循環(huán)調(diào)用得到字符串中所有匹配的子字符串 var s7 = "My name is JonHo, World Of Warcraft is my favourite game"; var positions = []; //用于存取找到的全部子字符串的索引值數(shù)組 var pos = s7.indexOf('a'); //找到第一個a, 進入循環(huán)while(pos > -1){ //當(dāng)找到a子字符串時(找不到會返回-1,大于-1即表示找到)進入循環(huán)positions.push(pos); //把找到的索引值(pos內(nèi)的內(nèi)容)push到positions數(shù)組內(nèi)pos = s7.indexOf('a', pos + 1); //每次循環(huán)都給上一次找到的a的索引值位置加1, 那樣能確保每次新的搜索都在上一次找到的子字符串(a)的索引值后一個值開始 }console.log(positions); //[4, 28, 32, 43, 53] //ES5的trim()方法, 會刪除字符串的前置及后置空格 var s8 = " My name is Jon. "; var trimmedString = s8.trim(); console.log(trimmedString); //My name is Jon. //字符串大小寫轉(zhuǎn)換, 常用的兩個, toLowerCase()和toUpperCase(), 還有兩個不常用的toLocaleLowerCase()和toLocaleUpperCase() //不常用的兩個方法通常會返回與前面兩個方法相同的結(jié)果, 但在少數(shù)語言中會為Unicode大小寫轉(zhuǎn)換應(yīng)用特殊的規(guī)則. var s9 = "My WOW player is Warlock."; var upperResult = s9.toUpperCase(); var lowerResult = s9.toLowerCase(); console.log(upperResult); //MY WOW PLAYER IS WARLOCK. console.log(lowerResult); //my wow player is warlock. //String的RegExp匹配方法, 略單體內(nèi)置對象(Global和Math)
Global是其實是終極對象, 在日常使用中不存在這個對象, 注意其屬性和某些特殊方法
Math對象的屬性和方法都是數(shù)學(xué)上常用的運算方法, 不詳述, 參見
https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Math
總結(jié)
以上是生活随笔為你收集整理的JavaScript知识点总结(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SQL Server 监控统计阻塞脚本信
- 下一篇: activiti监听器使用