今天主要给大家介绍js对象的属性操作
之前我们讲过对象的属性如何获取,常用的是通过.
来获取
亦或是使用obj[“name”] 获取,使用方括号和一个字符串,看起来是不是很像数组,其实这就是我们所说的关联数组,最常见的就是索引数组,我们通过索引来访问数组数据。
其实JavaScript中的所有对象都是关联数组,也称之为散列,映射或者是字典
关联数组
首先先让大家理解什么是关联数组
以名字的形式为元素赋值,这就形成了关联数组
var arr=[];
arr['name']='obj',
arr['sex']='nan'
console.log(arr) //[name: "obj", sex: "nan"]
这个就是最简单的关联数组,它是没有下标索引的,这个要注意
var arr=[];
arr['name']='obj',
arr['sex']='nan'
console.log(arr[0])//undefined
既然没有下标我们是没办法进行for of循环的
var arr=[];
arr['name']='obj',
arr['sex']='nan'
for(var value of arr){
console.log(value) 因为value是通过arr[index]获取的
}
相反 for in就可以
var arr=[];
arr['name']='obj',
arr['sex']='nan'
for(var item in arr){
console.log(item) // name sex
}
我们给数组增加两项原始值
var arr=[1,2];
arr['name']='obj',
arr['sex']='nan'
for(var value of arr){
console.log(value) 此时就可以打印 1 2
}
再看一下拼接能不能访问索引呢
var arr=[1,2];
arr['name']='obj',
arr['sex']='nan'
console.log(arr,arr[0],arr[2]) // [1, 2, name: "obj", sex: "nan"] 1 undefined
现在大家应该理解了什么是关联数组了吧,所以JavaScript所有的对象都是关联数组
正因为对象都是关联数组,所以我们只能通过名字访问值,名字是不能变的,但是我们的字符串是可变的,我们看这个例子
var customer={}
for(var i=0;i<4;i++){
customer['address'+i]=i
}
console.log(customer) //{address0: 0, address1: 1, address2: 2, address3: 3}
此时我们就可以通过 各个字符串设定了对象并可以获取相应的值,我们使用.
还需要一个个的赋值,相当的麻烦,很多场景使用数组写法非常方便,比如下面这个例子
var me={
name:'obj',
sex:'nan'
}
function addshuxing(me,hoby,game){
me[hoby]=game
}
对于对象的修改相当轻松,也可以使用for循环操作
属性的访问错误
之前我们讲过,属性是不存在报错的,报错的原因就是对象不存在,看下面的例子
var a='test'
console.log(a.length)//4
console.log(a.length.name)//undefined
console.log(a.length.name.sex)//'sex' of undefined
看过我前面文章的小伙伴看这个实在太容易解释了,a调用属性的时候继承了new String的属性,成功取到属性值,然后该属性下没有name属性,报了undefined 之后我们再调用name下的sex属性,此时就报错了,因为undefined没有构造函数形式,它是全局属性下的一个文字,注意一下即可
我们之前提过,对象的属性特点有可读,可配置,可枚举的,有一些属性是只读的,不能重新赋值,有一些对象不能新增属性,然而再它们不允许的情况下 事件是不会报错的
内置构造函数的属性是只读的
Object.prototype=0 //赋值失败,但没报错 Object.prototype并没有改变
只有在严格模式中才会报错
在以下场景中给对象(o)设置属性(p)会失败
1 ----o中的属性p是只读的;不能给只读的属性重新赋值(defineProperty()方法例外)
----o中的属性p是继承属性,且它只是只读的;不能通过同名自有属性覆盖只读的继承属性
----o中不存在自有属性p:o没有使用setter方法继承属性p,并且o的可扩展性是false。如果o中不存在p,并且没有setter方法调用,p一定会添加至o中。如果o不可扩展,那么o不能定义新属性
(不懂没有关系,以后讲到defineProperty的时候就没问题了)
删除属性操作
delete运算符可以删除对象的属性,我们来试试
var a={
name:'abc'
}
delete a.name
console.log(a.name) //undefined
然而delete只能删除自身属性,无法删除继承属性,要删除继承属性必须从定义这个属性的原型对象上删除,看例子
var a={
b:1
}
var p=Object.create(a)
console.log(p.b) //1
delete p.b
console.log(p.b)//1
delete a.b
console.log(p.b)//undefined
然而这种删除是不严谨的,我们看下面这个例子
var a={
p:{x:1}
}
b=a.p
console.log(b.x) //1
delete a.p
console.log(b.x) //1
引用依旧存在,因此在JavaScript的某些实现中,可能因为这种不严谨的代码导致内存泄漏,栈溢出。所以我们在销毁对象的时候,要遍历属性中的属性,依次删除
delete表达式删除成功或没有任何属性时,它返回true。如果delete后面不是一个属性访问表达式,也返回true
delete 1 //true
delete a.lengthxxxxxx //true
在非严格模式下,可以在全局注册属性,直接删除
this.a=6
console.log(a) //6
delete a
console.log(a) // 报错 a未定义
检测属性
判断属性是否存在于对象之中,可以通过in运算符、hasOwnProperty()和propertyIsEnumerable()方法,仅通过属性查询也可以做到
in运算符
var a={b:1}
'b' in a //true
'c' in a //false
'toString' in a //true 继承属性也是
hasOwnProperty()
var a={b:1}
a.hasOwnProperty('b') //true
a.hasOwnProperty('c') //false
a.hasOwnProperty('toString')// false 对于继承属性 将返回false
propertyIsEnumerable()就不演示了,它是hasOwnProperty()方法的增强版,如果属性是可枚举的并且不是继承的才返回true,之前在第二篇提过,可以使用for in 循环输出的都是可枚举
我们都知道属性如果存在就有名字跟值,我们可以通过对象.属性来判断,比如
o.x!==undefined 如果返回true就说明o对象存在x属性,当然如果x属性的值是undefined 这就打脑壳了
枚举属性
var arr=[1,2]
arr['add']='zhejiang'
for(var value in arr){
console.log(value) // 0 1 add 都是枚举属性
}
之前提过ESMAScript5之前 继承的方法也是可枚举的,因此我们继承的属性对象使用for in 循环也能找到继承的属性,如何让他们不循环呢,简单了解一下
for(p in o){
if(!o.hasOwnProperty(p)){
continue //跳过继承的属性
}
}
for(p in o){
if(typeof o[p]==="function"){
continue //跳过方法
}
}
利用extend()函数来操作对象的属性(函数这块我们以后有机会再讲) ----了解一下即可
function extend(o,p){
for(prop in p){ //注意这里遍历的是p
o[prop]=p[prop] //把p可枚举的属性 添加a
}
return o
}
还有其他工具函数,比如merge() restrict()有兴趣的可以了解一下
ES已经为们新定义了两个函数,帮助我们快速获得枚举属性
Object.keys()
var a={b:1,c:2}
console.log(Object.keys(a)) //[‘b',‘c']
返回的是一个数组
getOwnPropertyNames()返回的不仅仅是枚举,不过一般都是枚举属性
var a={b:1,c:2}
console.log(Object.getOwnPropertyNames(a)) //[‘b',‘c']