js对象的深入理解(三)

今天主要给大家介绍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()方法例外)

  1. ----o中的属性p是继承属性,且它只是只读的;不能通过同名自有属性覆盖只读的继承属性

  2. ----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']
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,772评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,458评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,610评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,640评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,657评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,590评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,962评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,631评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,870评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,611评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,704评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,386评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,969评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,944评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,179评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,742评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,440评论 2 342

推荐阅读更多精彩内容