JavaScript語法之對象
阿新 • • 發佈:2018-07-19
get 成對 pan 子類 var 對象類型 des ret prototype 今天總結一下關於對象的重點和容易理解不清的知識點。
1 JavaScript中主要有兩種類型,即基本類型(包括string,number,boolean,null,undefined)和對象。而函數,數組,內置對象(String,Number,Boolean,Object,Function,Array,Date,RegExp,Error),這些都是對象的子類型(也可以叫復雜基本類型)。也就是說它們也是對象的一種類型,具備一些額外的行為,比如函數可以理解為可調用的對象。因為函數是對象的一種子類型,所以函數可以當作另一個函數的參數。
存儲在對象容器內部的是這些屬性的名稱, 它們就像指針(從技術角度 來說就是引用) 一樣, 指向這些值真正的存儲位置。
例如:
var obj={
func:function(){
console.log(this);
}
};
從技術角度來說, 函數永遠不會“屬於” 一個對象。所以,對象裏的方法,本質上是對象裏的一個屬性名指向一個函數。對象通過屬性訪問返回的函數和其他函數沒有任何區別,除了this發生隱式綁定。
2 關於函數的拷貝
淺拷貝,深拷貝:
由於對象的實例是存儲在堆內存中然後通過一個引用值去操作對象,因此拷貝的時候就出現兩種情況:拷貝引用和拷貝實例,這就是淺拷貝和深拷貝的區別。可以說,淺拷貝只拷貝一層實例,深拷貝是拷貝所有層的實例。
淺拷貝,是拷貝引用,拷貝後的引用都是指向同一個對象的實例,彼此之間的操作會互相影響。淺拷貝的外層源對象是拷貝實例,內層元素是拷貝引用。就是說,外面的整個對象肯定是復制一個新的實例,裏面的元素,如果是基本類型的值,肯定也是復制值,如果是數組或者對象這樣的對象類型,則是復制其引用。
常用方法:Array.prototype.slice(), Array.prototype.concat() 但是這兩個函數都是用於數組。
若要淺拷貝對象,有var newObj = Object.assign( {}, myObject );,jQUery的extend,還可以:
var obj = { a:1, arr: [2,3] };
var shallowObj = shallowCopy(obj);
function shallowCopy(src) {
var dst = {};
for (var prop in src) {
if (src.hasOwnProperty(prop)) {
dst[prop] = src[prop];
}
}
return dst;
}
例子:
var a = [{c:1}, {d:2}];
var b = a.slice();
console.log(a === b); // 輸出false,說明外層數組拷貝的是實例
a[0].c = 3;
console.log(b[0].c); // 輸出 3,說明其元素拷貝的是引用
深拷貝:在堆中重新分配內存,並且把源對象所有屬性都進行新建拷貝,以保證深拷貝的對象的引用圖不包含任何原有對象或對象圖上的任何對象,拷貝後的對象與原來的對象是完全隔離,互不影響
常用方法:JSON var newObj = JSON.parse( JSON.stringify( someObj ) )。另外可以用遞歸函數。
綜合的深拷貝函數:
var cloneObj = function(obj){
var str, newobj = obj.constructor === Array ? [] : {};
if(typeof obj !== ‘object‘){
return;
} else if(window.JSON){
str = JSON.stringify(obj), //系列化對象
newobj = JSON.parse(str); //還原
} else {
for(var i in obj){
newobj[i] = typeof obj[i] === ‘object‘ ?
cloneObj(obj[i]) : obj[i];
}
}
return newobj;
};
例子:
var a = {c: {d: 1}};
var b = $.extend(true, {}, a);
console.log(a === b); // 輸出false
a.c.d = 3;
console.log(b.c.d); // 輸出 1,沒有改變。
3 屬性與屬性描述符
所有屬性都有4種屬性描述符(或叫數據描述符),分別是value(數據值),writable(可寫的),enumerable(可枚舉的),configurable(可配置的)。
若要查看某個屬性的屬性描述符,可以用:
Object.getOwnPropertyDescriptor( myObject, "屬性名" );
若要修改某個屬性的屬性描述符,可以:
var myObject = {};
Object.defineProperty( myObject, "a", {
value: 2,
writable: true,
configurable: true,
enumerable: true
} );
myObject.a; // 2
writable,設置為false後表示不可寫,則無法改變該屬性的值。
enumerable,設置為false後,該屬性無法出現在對象的屬性枚舉中,如for...in循環中遍歷不到這個屬性。
configurable,設置為false後,該屬性變為不可配置,所以再想改回來是不可以的,即configurable改為false是單向操作。同時,設置為false後,用delete刪除這個屬性無效。
4 屬性的getter和setter
getter和setter是隱藏函數,分別會在獲取屬性值和設置屬性值時調用。因此,可以用getter和setter來改寫單個屬性的默認操作。
可以有兩種格式去修改屬性的默認操作:
var myObject = {
// 給 a 定義一個 getter
get a() {
return 2;
}
};
或:
Object.defineProperty(
myObject, // 目標對象
"b", // 屬性名
{ // 描述符
get: function(){ return this.a * 2 },
// 確保 b 會出現在對象的屬性列表中
enumerable: true
}
);
一般要給一個屬性設置屬性值時,getter和setter是成對出現的:
var myObject = {
// 給 a 定義一個 getter
get a() {
return this._a_;
},
// 給 a 定義一個 setter
set a(val) {
this._a_ = val * 2;
}
};
myObject.a = 2;
myObject.a; //4
歡迎互相交流,互相學習。前端開發QQ群:711357426
JavaScript語法之對象