js紅寶書學習
1. number型別
八進位制字面值的第一位必須是0,後續數字序列在0-7之間,若是數值超出了範圍,前導0將被忽略,後面的數值將被當做十進位制數值解析:
var octalNum = 070;//八進位制的56
var ocyalNum = 079;// 解析為79
八進位制字面量在嚴格模式下無效,JavaScript引擎會丟擲錯誤。
十六進位制面值的前兩位必須是0x,後跟0-9或者A-F。
在進行算術計算時,所有以八進位制和十六進位制表示的數值最終都將被轉換成十進位制數值。
1.1 浮點數
數值中必須包含一個小數點;儲存浮點型需要的空間是整形數值的兩倍。
2. 作用域
Javascript中沒有塊級作用域的概念。但是函式會有作用域。但是if()、for{}不會形成塊級作用域,與Java語言不一樣。Javascript中沒有塊級作用域的概念。但是函式會有作用域。但是if()、for{}不會形成塊級作用域,與Java語言不一樣。
在JavaScript中,for語句建立的變數i在for迴圈結束後,會依舊存在外部的執行環境中,因此可以訪問到變數i的值。
for(var i=0;i<3;i++){
console.log(i)
};
alert(i);
VM86: 0
VM86: 1
VM86: 2
console.log(i)
VM98: 3
函式內部存在與全域性環境中同名變數時,在函式內部訪問該變數會先找區域性環境中即函式體內是否存在該變數標識,若沒有再沿著作用域鏈向上一級尋找。區域性變數訪問速度比訪問全域性變數速度快。
3. 垃圾收集
—標記清除
定義:對進入執行環境(如函式內定義的變數)標記為“進入環境”,當離開時記錄為“離開環境”這時可以進行清除。
原理:被標記的變數視為準備刪除的變數。垃圾回收機制可以進行記憶體清除,銷燬帶標記的值並回收它們佔用的空間。
—引用計數
定義:跟蹤記錄每個值被引用的次數。
原理:當變數的被引用次數為0時,就可以回收該變數。
問題:當變數A和B之間迴圈引用時,由於使用引用計數,所以在當函式執行完畢後,A和B的引用仍然不為0,因此不會被垃圾回收,這就有可能會導致記憶體無法釋放。
var element = document.getElementById("some_element");
var myObject = new Object();
//存在迴圈引用
myObject.element = element;
element.someObject = myObject;
為了避免這種迴圈引用的問題,可以在不使用它們的時候手工切斷之間的連線,如:
myObject.element = null;
element.someObject = null
4. 資料屬性和setter、getter訪問器屬性
可通過object.defineProperty()定義下屬四個屬性
—configurable:表示是否可以用delete刪除屬性以重新定義屬性
—enumerable:是否可以用for-in迴圈返回屬性
—writable:是否可以修改屬性值
—value:表示屬性的資料值
以上預設都是FALSE。
5. split()用正則表示式進行分割
在返回的陣列中第一個和最後一個是空字串,因為正則表示式的意思為“ 用不是“,”的字元作為分割字串 ”–那麼分割字串就是“red blue green yellow”。因為red之前沒有字元,所以分割完是空字串。
var text=",blue,red,yellow";
var rusult=text.split(",");
console.log(rusult);
//輸出為: ["", "blue", "red", "yellow"]
6. round(),ceil(),floor()對負數的處理
Math.round(-1.6); //-2
Math.round(-1.1); //-1
Math.floor(-1.7); //-2
Math.ceil(-1.7); //-1
7. randow()返回>=0的<1的數
值=Math.floor(Math.randow()*可能值的總數+第一個可能出現的值)
8. JS對URL的編碼方法
—escape(): 用的比較少了,返回的是一個字元的Unicode編碼值。
—encodeURI(): 對URL進行編碼的函式,但是對於特殊字元比如&[email protected];:#/?, 不會編碼,對應的解碼函式為decodeURI()。
----encodeURIComponent(): 可以針對特殊字元比如&[email protected]/?;:,進行編碼,對於的解碼函式為decodeURIComponent();
9. 深拷貝和淺拷貝
在js中儲存方式是分棧和堆,一般基礎型別是棧儲存,複雜型別如物件和陣列一般是堆儲存。
深拷貝和淺拷貝是對於複雜型別而言的。
案例說明:深拷貝、淺拷貝、賦值的區別
var obj1 = {
'name' : 'zs',
'age' : '18',
'language' : [1,[2,3],[4,5]],
};
var obj2 = obj1; //利用賦值
var obj3 = shallowCopy(obj1); //利用淺拷貝的方式
function shallowCopy(src) {
var result = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
result[prop] = src[prop];
}
}
return result;
}
obj2.name = "lisi"; //改變obj2屬性基本型別name的值
obj3.age = "20"; //改變obj3屬性基本型別age的值
obj2.language[1] = ["二","三"]; //改變obj2中language陣列型別的值
obj3.language[2] = ["四","五"]; //改變obj3中language陣列型別的值
console.log(obj1); //obj的name由於obj2的更改受到了影響,但是obj3改變age值對obj1沒有影響。
//obj1 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj2);
//obj2 = {
// 'name' : 'lisi',
// 'age' : '18',
// 'language' : [1,["二","三"],["四","五"]],
//};
console.log(obj3);
//obj3 = {
// 'name' : 'zs',
// 'age' : '20',
// 'language' : [1,["二","三"],["四","五"]],
//};
由上述程式碼可知:複雜型別的賦值會和原物件指向同一個記憶體地址;複雜型別的淺拷貝對於物件中的巢狀引用型別的資料(如language)只會拷貝引用(即拷貝language變數儲存的指標地址),而物件中的簡單型別是相當於另外開闢了一個儲存空間。所以obj3的language的改變會影響到obj1,因為obj3中language和obj1的language是指向了一塊儲存空間。而obj3的age不會影響到obj1的age屬性。
和原資料是否指向同一物件 | 第一層資料為基本資料型別 | 原資料中包含子物件 | |
---|---|---|---|
賦值 | 是 | 因為和原物件指向同一個地址,所以改變會影響原資料 | 改變會影響到原資料 |
淺拷貝 | 否 | 改變不會影響原資料 | 改變會影響原資料,因為只拷貝了子物件的引用 |
深拷貝 | 否 | 改變不會影響原資料 | 改變不會影響原資料 |
深拷貝可以用遍歷實現,如下:
寫法1
var deepCopy = function(obj) {
if (typeof obj !== 'object') return;
// 根據obj的型別判斷是新建一個數組還是一個物件
var newObj = obj instanceof Array ? [] : {};
for (var key in obj) {
// 遍歷obj,並且判斷是obj的屬性才拷貝
if (obj.hasOwnProperty(key)) {
// 判斷屬性值的型別,如果是物件遞迴呼叫深拷貝
newObj[key] = typeof obj[key] === 'object' ? deepCopy(obj[key]) : obj[key];
}
}
return newObj;
}
寫法2
function deepClone(obj1,obj2) {
var o = obj2||{};
for(var key in obj1) {
if(typeof obj1[key]==='object'){
o[key] = (obj1[key].constructor=== Array)?[]:{};
deepClone(obj1[key],o[key]);
}else {
o[key] = obj1[key];
}
}
return o;
}