对象的简单认识

对象

对象其实可以看做有许多键值对组合成的一个无序集合,可以通过键俩访问值。值一般由,基本数据类型 和 object 组合。

对象的创建

有三种方式:

1. new构造函数

  1. 使用new来创建一个对象
    var person = new Object();
    甚至可以简写成为: var person = new Object;

  2. Object参数如果是一个对象,则直接返回对象本身

var o = { a : 1};
var p = new Object(o);
alert(o === p); // true
  1. 传入原始数据类型,则返回包装对象
var o1 = new Object("123");
console.log(o1); // String{0:"1",1:"2",2:"3",length:3,__proto__: String, [[PrimitiveValue]]: "123"}

var o2 = new Object(123);
console.log(o2) // Number{123, __proto__: Number, [[PrimitiveValue]]: 123} 

var o3 = new Object(true);
console.log(o3)
// Boolean {__proto__: Boolean, [[PrimitiveValue]]: true}

// ------------ 下面是空对象 和不传参数一样。
var o4 = new Object(null)
console.log(o4) // Object{__proto__: Object}

var o5 = new Object(undefined)
console.log(o5) // Object{__proto__: Object}

var o6 = new Object()
console.log(o6) // Object{__proto__: Object}

2. 对象字面量

这是我们 最熟悉的一种,也是经常使用的一种,其实使用字面量只是隐藏了与使用new操作符相同的基本过程,于是也可以叫做语法糖。
简单示例:

var person = {
	age : 24,
	name: 'xiaoming',
	1: true,  
}

注意,使用对象字面量方法来定义对象的时候,属性名会自动转化为字符串。
就是上面示例,自动变成下面的。

var person = {
	'age' : 24,
	'name': 'xiaoming',
	'1': true,  
}

Object.create()

ES5定义了一个名为Object.create()的方法,它创建一个新对象,第一个参数就是这个对象的原型,第二个可选参数用以对对象的属性进行进一步描述

var o = Object({a:1})
console.log(o) // Object{a:1,__proto__:object}

注意:传入参数null来创建一个没有原型的新对象

var o1 = Object.create(null); 

var o2 = {};

此时o1不会继承任何东西,甚至不包括基础方法。比如toString()和valueOf()。
如果想要创建一个普通的空对象(例如,通过{}或new Object()创建的对象),需要传入Object.prototype, 这就是因为,这个函数的第一个参数就是原型对象。

var o3 = Object.create(Object.prototype);
var o4 = {};

对象的引用

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。

var o = {
	a:1,
}

var p = o;
console.log(p.a)  // 1

p.a = 0;
console.log(o.a) // 0

对象的属性

对象的属相操作,有两种 [] 和 点号(.)。
点号(.), 在使用的时候,属性名必须符合标识符的命名规则。
不存在的属性取值返回undefined。

var o = {
	a : 0,
	1 : true,
}

o.b = 1;  // 可以增加属性,并赋值
console.log(o.a) // 可以取值操作
console.log(o.1) // 报错
console.log(o.b)  // undefined  不存在的变量
o.a = 2;  // 可以赋值操作
console.log(o.a);

[] 方括号中的值, 若是字符串,则直接访问。 如果非字符串类型且不符合标识符命名,则转成字符串访问,如果非字符串类型且符合标识符命名,则需要识别变量的值,变量未定义,则报错。
在[] 访问属性的时候 是可以计算属性的

var c = 1;
var o = {}

console.log(o[0]) // undefined   o[0] --> o['0'] 访问。
console.log(o[a]) // 报错,a符合变量的命名规则,a未被定义,而报错

console.log(o['a']) // undefined    o['a'] 访问。
console.log(o[null]) // undefined , o[null] --> o['null']访问

console.log(o[c + 1]) // undefined  o[c+1] --> o['4']访问

注意 null和undefined不是对象,给它们设置属性会报错

属性的删除

使用delete运算符可以删除对象属性(包括数组元素)。
delete是有返回值的,删除成功则返回true,删除不存在的属性或非左值时,返回false。当使用delete操作符删除不可配置的属性时,返回false,严格模式下会抛出TypeError错误
将属性赋值为 null 和undefined 只是修改了属性的值。

var o = {
	a:1
}
console.log(delete o.a);//true
console.log(o.a);//undefined
console.log('a' in o);//false   in 操作符 可以判断对象是否具有该属性,但是无法判断是否是继承来的

使用delete删除数组元素时,不会改变数组长度

var a = [1,2,3];
delete a[2];
2 in a;//false
a.length;//3

属性的检测

每一个javascript对象都和另一个对象相关联。“另一个对象”就是我们熟知的原型对象,每一个对象都会从原型对象继承属性。
对象本身具有的属性叫自有属性,从原型对象继承而来的属性叫继承属性

in: in操作符可以判断对象是否可以使用某一属性,但无法区别自有还是继承属性
for-in: for-in循环可以遍历出该对象中所有可枚举属性
hasOwnProperty(): 可以确定该属性是自有属性还是继承属性
Object.keys(): 返回所有可枚举的自有属性
Object.getOwnPropertyNames(): Object.keys()方法不同,Object.getOwnPropertyNames()方法返回所有自有属性(包括不可枚举的属性)

属性描述符

对象属性描述符分为, 数据属性 访问器属性

数据属性

数据属性(data property)包含一个数据值的位置,在这个位置可以读取和写入值。

  1. 可配置configuable

    • 可配置性决定是否可以使用delete删除属性,以及是否可以修改属性描述符的特性,默认值为true
    var o = {a:1};
    Object.defineProperty(o,'a',{
        configurable:false,
    });
    delete o.a; //false   严格模式下报错
    console.log(o.a);//1
    
    • 设置Configurable:false后,将无法再使用defineProperty()方法来修改属性描述符
    var o = {a:1};
    Object.defineProperty(o,'a',{
        configurable:false
    });
    // 报错不能修改属性
    Object.defineProperty(o,'a',{
        configurable:true
    });
    
    • writable的状态 只能是从true变为false
  2. 可枚举enumerable
    可枚举性决定属性是否出现在对象的属性枚举中,具体来说,for-in循环、Object.keys方法、JSON.stringify方法是否会取到该属性。

    var o = {a:1};
    Object.defineProperty(o,'a',{enumerable:false});
    for(var i in o){
        console.log(o[i]);//undefined
    }
    
  3. 可写性writable
    可写性决定是否可以修改属性的值,默认值为true

    var o = {a:1};
    Object.defineProperty(o,'a',{
        writable:false
    });
    console.log(o.a);//1
    o.a = 2;//由于设置writable为false,所以o.a=2这个语句会默认失效,严格模式会报错
    console.log(o.a);//1
    
  4. 属性值value
    属性值包含这个属性的数据值,读取属性值的时候,从这个位置读;写入属性值的时候,把新值保存在这个位置。默认值为undefined

访问器属性

访问器属性不包含数据值;它们包含一对儿getter和setter函数(不过,这两个函数都不是必需的)。在读取访问器属性时,会调用 getter函数,这个函数负责返回有效的值;在写入访问器属性时,会调用setter函数并传入新值,这个函数负责决定如何处理数据。

  1. 可配置性Configurable
      表示能否通过 delete 删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。像前面例子中那样直接在对象上定义的属性,它们的这个特性默认值为 true
  2. 可枚举性Enumerable
    可枚举性决定属性是否出现在对象的属性枚举中,比如是否可以通过for-in循环返回该属性,默认值为true
  3. getter 读
      在读取属性时调用的函数。默认值为undefined
  4. setter 写
      在写入属性时调用的函数。默认值为undefined
      和数据属性不同,访问器属性不具有可写性(Writable)。如果属性同时具有getter和setter方法,那么它是一个读/写属性。如果它只有getter方法,那么它是一个只读属性。如果它只有setter方法,那么它是一个只写属性。读取只写属性总是返回undefined

get是一个隐藏函数,在获取属性值时调用。set也是一个隐藏函数,在设置属性值时调用,它们的默认值都是undefined。Object.definedProperty()中的get和set对应于对象字面量中get和set方法
[注意]getter和setter取代了数据属性中的value和writable属性
通常这里的get和set是用来 拦截数据访问和修改的。

var o = {
	get a(){
		return 0;
	}
}

console.log(o.a)  // 0
o.a = 1 // 没有set方法, 默认失效
console.log(o.a)  // 0
// ---------------------------------------
Object.defineProperty(o,'b',{
    get: function(){
        return 2;
    }
})
console.log(o.b);//2
//由于没有设置set方法,所以o.a=3的赋值语句会静默失败
o.b = 1;
console.log(o.b);//2

只有set

var o = {}
Object.defineProperty(o,'a',{
    set: function(){
        return 0;
    }
})
o.a = 1;
console.log(o.a);//undefined

通常情况下 get 和set是成对出现的, 并且你会发现,这样做,我们还需要空间来存储值。 这也是数据属性的不同之处吧。

var o = {};
Object.defineProperty(o,'a',{
    get: function(){
        return this._a;
    },
    set :function(val){
        this._a = val*2;
    }
})
o.a = 1;
console.log(o.a);//2

对象属性的获取和设置

  1. Object.getOwnPropertyDescriptor(对象,属性名)
    查看对象的属性,返回一个对象,包含了属性的特性。,当查看不存在的属性时,返回undefined。 并且只适用于自身的属性。
var o = {a : 0};
// Object {value: 0, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
// undefined
console.log(Object.getOwnPropertyDescriptor(o,'b')); 
  1. Object.defineProperty(对象,属性名, 属性描述)
    返回配置后的对象。
    使用该方法创建或配置对象属性的描述符时,如果不针对该属性进行描述符的配置,则该项描述符默认为false
var o = {};
Object.defineProperty(o,'a',{
		value: 0,
		writable: true,
		enumerable: true,
	});
// /{value: 1, writable: true, enumerable: true, configurable: false}     没有配置由于没有配置configurable,所以它的值为false
console.log(Object.getOwnPropertyDescriptor(o,'a'))
  1. Object.defineProperties(o, 属相描述)
    用于创建或配置对象的多个属性的描述符,返回配置后的对象。
var o = {
	a : 1,
}

Object.defineProperties(o,{
	a:{enumerable:false},
	b:{value:2}
})

//{value: 1, writable: true, enumerable: false, configurable: true}
console.log(Object.getOwnPropertyDescriptor(o,'a'));
//{value: 2, writable: false, enumerable: false, configurable: false}
console.log(Object.getOwnPropertyDescriptor(o,'b'));
  1. Object.create(原型对象,描述)
    使用指定的原型和属性来创建一个对象。
var o = Object.create(Object.property,{
	a:{
		value: 0,
		writable: false,
		enumerable: true,
	},
	b{
		value: 1,
	}
})
//{value: 0, writable: false, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj,'a'));
// {value: 1, writable: true, enumerable: true, configurable: true}
console.log(Object.getOwnPropertyDescriptor(obj,'b'))

对象的拷贝

浅拷贝

使用for-in将对象的所有属性复制到新建的空对象中,并将器返回

function simpleClone(o,cloneObj){
	// 判断参数
    for(var i in obj){
        cloneObj[i] = obj[i];
    }
    return cloneObj;
}

使用属性描述符

function simpleClone(o){
	// 判断参数
	var cloneObj = Object.create(Object.getPrototypeOf(o)); // 根据o对象的原型对象,创建新对象。
	// 获取自身属性并迭代。 
	Object.getOwnPropertyNames(o).forEach(function(propKey){
		// 根据自身属性名 获取属相描述。
        var desc = Object.getOwnPropertyDescriptor(o,propKey);
        // 给克隆对象设置 属性描述
        Object.defineProperty(cloneObj,propKey,desc);
    });
    return cloneObj;
}

深拷贝

复制对象的属性时,对其进行判断,如果是数组或对象,则再次调用拷贝函数;否则,直接复制对象属性

function deepClone(o,cloneObj){
	if(typeof o != 'object'){
        return false;
    }
    var cloneObj = cloneObj || {};  // 保证cloneObj不是null和undefined

    for(var i in o){
		if(typeof o[i] === 'object'){ // 是对象继续递归拷贝
			cloneObj[i] = (o[i] instanceof Array) ? [] : {};
            arguments.callee(o[i],cloneObj[i]);
		}else{
			cloneObj[i] = o[i];
		}
    }

}

使用 json.
先是对象转成字符串,然后在转成对象返回。

function jsonDeepClone(o){
	return JSON.parse(JSON.string(o))
}
posted @ 2019-03-07 16:59  Cyrus_Br  阅读(258)  评论(0编辑  收藏  举报