JS數據類型
var str = 'abc';
var num = 123;
var bool = true;
var und = undefined;
var n = null;
var arr=['x','y','z'];
var obj = {};
var fun = function() {};
console.log(typeof str); //string
console.log(typeof num); //number
console.log(typeof bool); //boolean
console.log(typeof und); //undefined
console.log(typeof n); //object
console.log(typeof arr); //object
console.log(typeof obj); //object
console.log(typeof fun); //function
對象
對象常用屬性和方法
SON.stringify() 方法是將一個JavaScript值(對象或者數組)轉換為一個 JSON字符串; JSON.parse() 方法用于將一個 JSON 字符串轉換為對象。
hasOwnProperty() 該方法可以判斷對象的自有屬性是否存在
assign() 該方法主要用于對象的合并,Object.assign(o1,o2)
defineProperties()直接在一個對象上定義新的屬性或修改現有屬性,并返回該對象。
keys() 返回一個由一個給定對象的自身可枚舉屬性組成的數組,Object.keys(o);
values();返回一個給定對象自己的所有可枚舉屬性值的數組
entries();返回一個給定對象自身可枚舉屬性的鍵值對數組
屬性的設置和獲取
1、設置屬性
var obj = {};
obj.name='aaaa';
obj['age'] = 20;
2、獲取屬性
obj.name;
obj['age'];
3、屬性的刪除
var o2= { name:'abc', age:18 };
delete o2.name; ? ?
console.log(o2);
檢測屬性
檢測屬性 該方法可以判斷對象的自有屬性是否存在
in 運算符 檢測屬性是否存在于某個對象中,自有屬性和繼承屬性都返回true
var obj={ name:'sonia', age:22 };
console.log('name' in obj);//自有屬性
引用類型如何深拷貝
//引用類型深拷貝?結果證明是淺拷貝
//如果對象只有一級屬性,Object.concat可以實現深拷貝
var arr1 = [1,2,3,[4,5]]
var arr2 = arr1.concat()
arr1.push(11)
arr1[3][0]=100;
console.log(arr1);
console.log(arr2);//Object.assign對于對象1級屬性,可以是深拷貝,多級屬性是淺拷貝
var o1= {id:10}
var o2 = Object.assign({},o1);
o1.id = 100
console.log(o1.id);
console.log(o2.id);var o1= {id:10,test:'o1',children:{v:'o1'}}
var o2 = Object.assign({},o1);
o1.id = 100
o1.children.v='v2';
console.log(o1);
console.log(o2);
最簡單的深拷貝方法是序列化
var obj = {name: "fangfang",age: 18,children: { id: 1 },};var obj2 = JSON.parse(JSON.stringify(obj));obj.name = "alice";obj2.children.id = 99;console.log(obj);console.log(obj2);
但是序列化實現深拷貝有很多坑:
- 如果obj里存在時間對象,JSON.parse(JSON.stringify(obj))之后,時間變成了字符串
- 如果obj里有RegExp、Error對象,則序列化后的結果只得到空對象
- 如果obj里有函數、undefined,則序列化的結果會把函數undefined丟失
- 如果obj里有NaN,Infinity,則序列化的結果會變成null
- JSON.stringify只能序列化對象的可枚舉的自有屬性。如果obj中的對象是由構造函數生成的,則使用JSON.parse()深拷貝后,會丟棄對象的constructor
- 如果對象中存在循環引用的情況,也無法進行正確的深拷貝
自定義深拷貝方法
function deepCopy(newObj, obj) {var o = newObj;for (var key in obj) {if (typeof obj[key] === "object") {//判斷obj[key]的類型,是數組還是對象,使用constructor嚴格判斷對象是由誰構造出來的o[key] = obj[key].constructor === Array ? [] : {};deepCopy(o[key], obj[key]);} else {o[key] = obj[key];}}return o;}
預解析
JavaScript預解析,可以理解為把變量或者函數預先解析到使用的環境中
console.log(a);
var a = 10;
//結果輸出undefined
預解析過程
第一步:預先解析var、function等,提升聲明變量
第二步:預解析完畢后,逐行正常由上而下解析
f();//error
//函數表達式
var f = function () {};fn();//OK
//函數聲明
function fn() {}//函數表達式和函數聲明的最大區別是:預解析。函數聲明有預解析功能
//也就是function聲明的函數會在執行前提前解析
如果變量名和函數名相同了,誰的優先級高?
console.log(f);
function f(){console.log("456");
}
var f = 123;
//結果輸出:[Function: f]console.log(f);
var f = 123;
function f(){console.log("456");
}
//結果還是輸出:[Function: f]
同名函數和變量,函數的優先級會更高,也就是函數取代變量。
方法內部也存在預解析:
var b = 10;function f3() {console.log(b);var b = 100;}f3(); //undefined/**************解析過程***************/var b;function f3(){}b=10;f3();//f3方法內部預解析var b;console.log(b);//此時是undefinedb=100;
作用域
作用域:它是指對某一變量和方法具有訪問權限的代碼空間,在JS中, 作用域是在函數中維護的。
表示變量 或函數起作用的區域,指代了它們在什么樣的上下文中執行,亦即上下文執行環境
ES5的作用域只有兩種:全局作用域和局部作用域(局部作用域又叫函數作用域)
var a = 1;
//if(true)的語句執行完成之后會自動銷毀,從而將var a = 10,提升為全局變量
if (true) {
var a = 10;
}
console.log(a); //輸出10
全局變量和局部變量同名的坑:
1、在全局變量和局部變量不同名時,其作用域是整個程序
2、在全局變量和局部變量同名時,全局變量的作用域不包含同名局部變量的作用域
var c = 30;
function f2(){var c;console.log(c);
}
f2();//undefined
作用域鏈
執行函數的時候,先從函數內部尋找變量,如果找不到,會向創建函數的作用域內尋找變量
var a = 1;function f1() {var a = 10;function f2() {var a = 20;console.log(a);//20}function f3() {console.log(a);//10}f2();f3();}f1();console.log(a);//1