一、对象概述

对象中包含一系列的属性,这些属性是无序的。每个属性都有一个字符串key和对应的value。

var obj={x:1,y:2};
obj.x;
obj.y;

1、为什么属性的key必须是字符串

重点

可见,字符串的1和数字1访问的都是同一个属性

不管把空对象作为一个key,还是用带有x属性的对象作为key,实际上javascript都会把它转化为字符串,会toString()一下再去处理。所以最终依然指向同样一个属性。

2、对象结构

1、对象属性的结构

  • 对象的属性可以动态添加和删除
  • 对象的每个属性都有一些标签。

这些标签为每个属性提供访问权限的控制,比如是否可写(writable),是否可以被删除掉(configurable),是否可枚举(enumerable)。

var obj={x:1,y:2};
obj.x;
obj.y;

这段代码对应的结构:

2、对象的原型

每个对象都有一个原型[[proto]]

function foo(){}
foo.prototype.z=3;var obj=new foo();

上面这段代码对应的obj的结构如下:

3、对象的标签

对象除了[[proto]]标签还有[[class]]标签和[[extensible]]标签。

[[class]]标签标示对象是属于哪个种类的。

[[extensible]]标签标示对象是否允许增加新的属性。

所以一个对象完整的结构如下:

二、创建对象、原型链

1、创建对象的方式有哪些

1、对象字面量创建对象

可以嵌套

var obj1={x:1,y:2};var obj2={x:1,y:2,o:{z:3,n:4}};

2、new构造器的方法创建

原型链结构

function foo(){}
foo.prototype.z=3;

var obj=new foo();
obj.y=2;
obj.x=1;

通过new去构造对象的特点:它的原型会指向构造器的prototype属性。

这么做的作用:通过原型链继承,继承原型上的属性和方法。

当访问一个属性,这个对象上没有该属性,通过原型链向上查找,一直找到null,还没有就返回undefined。

注意:

obj.z返回undefined,不一定是没有z属性,也可能是z=undefined。也可能是向上查找原型链没找到返回undefined。一个对象是否有某个属性,可以通过in或者hasOwnProperty方法来确认。

3、Object.create创建对象

Object.create是系统内置的函数,这个函数会接收一个参数,一般是一个对象,它会返回一个新创建的对象,并且让对象的原型指向这个参数。

对应的结构为:

用字面量创建的对象{x:1}也是有原型的,它的原型指向Object.prototype,所以在obj上仍然可以用obj.toString这个方法,并且由于是从原型链上继承的,并不是对象本身的属性,所以obj.hasOwnProperty('x')会返回false。

注意:

并不是所有的对象都有toString(),因为并不是所有的对象的原型链上都有Object.prototype。

如果用Object.create(null)传入一个null的话,它的原型就直接就是null了。这样它就不会包含任何方法,

三、属性操作

1、读写对象属性

可以用.操作符或者[]。

一般情况用.操作符更好一点,有些编辑器可以自动检查。

需要拼属性名的时候往往需要用[]。

除了用for循环拼接属性名,也可以用for in循环。for in有可能把原型链上的属性也遍历出来,并且是无序的。

2、属性异常

obj.y会查找原型链,一直找到末端是null还是没有的话就返回undefined。

obj.y.z,obj.y不存在是undefined,再去访问或者写入z,就会报错不能read或者set 一个undefined属性z。

重点

所以在做一些出来时经常要先做些判断,比如

var yz;
if(obj.y){yz=obj.y.z
}

技巧:巧用运算符的规则

var yz=obj&&obj.y&&obj.y.z;

3、删除属性

重复删除已经不存在的属性,不会做任何事情,但是因为属性已经不存在了,仍然会返回true。

注意:delete并不表示操作生效了或者成功了,只表示这个对象上已经不存在delete的这个属性。

特殊情况:

有些属性是不允许被删除的,比如Object.prototype。

顺便说一下其他

用var定义的全局变量也不能被删除。

隐式声明的全局变量可以被删除。

局部变量,函数声明,函数内部的函数声明都是不可被delete掉的。

了解更多参考:javascript var变量删除

4、检测属性

 <script type="text/javascript">var cat=new Object;cat.legs=4;cat.name="Kitty";//属性检测console.log('legs' in cat);  //trueconsole.log('abc' in cat); //falseconsole.log('toString' in cat); //true ,继承来的属性
console.log(cat.hasOwnProperty('legs'));      //trueconsole.log(cat.hasOwnProperty('toString'));   //false//查看属性是否可枚举console.log(cat.propertyIsEnumerable('legs'));    //trueconsole.log(cat.propertyIsEnumerable('toString')); //false//输出cat的属性和对应的值for(p in cat){console.log(p+" "+cat[p]);}/**legs 4name Kitty/</script>

自定义一个不可枚举的属性。

Object.defineProperty(cat,'price',{enumerable:false,value:1000});
//Object {legs: 4, name: "Kitty", price: 1000}
cat.propertyIsEnumerable('price');
//false
cat.hasOwnProperty('price');
//true

注意:

用Object.defineProperty定义的属性,默认的enumerable,writable,configurable标签都是false,所以这里的enumerable也可以不写。

5、枚举属性

var o={x:1,y:2,z:3};
'toString' in o
//true
o.propertyIsEnumerable('toString')
//false
var key;
for(key in o){console.log(key);
}
/*
x
y
z
*/

for in枚举

var o={x:1,y:2,z:3};var obj=Object.create(o);obj.a=4;var key;for(key in obj){console.log(key);//a,x,y,z}

如果只想枚举对象上的属性,加上hasOwnProperty判断

 var o={x:1,y:2,z:3};var obj=Object.create(o);obj.a=4;var key;for(key in obj){if(obj.hasOwnProperty(key)){console.log(key);//a
        }}

此外遍历数组可以用forEach方法,

也可以用Object.keys()来获取对象上的所有key.

四、get/set方法

另一种读写属性的方式

get,set也叫访问器属性,包含一对getter和setter函数。访问器属性有下面4个特征:【update20170320】

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为数据属性
  • [[Enumerable]]:表示能否通过for-in循环返回属性。
  • [[Get]]:在读取属性时调用的函数。默认值undefined。
  • [[Set]]:在写入属性时调用的函数。默认值undefined。

1、get,set

get,set方法和其他属性区别很大, 以get,set关键字开头,紧接着对应的属性的名字,后面是个函数体。get,set方法与一般属性之间仍然是用逗号隔开。

var man={name:'Bosn',weibo:'@Bosn',get age(){return new Date().getFullYear()-1988;},set age(val){console.log('Age can\'t be set to '+val);}
}console.log(man.age);   //29
man.age=100; //Age can't be set to 100
console.log(man.age);     //still 29

也可以写成:

get:function age() {};

例2:【update20170320】

//console运行
var book={_year:2004,edition:1
};
Object.defineProperty(book,"year",{
get:function(){return this._year;
},
set:function(newValue){if(newValue>2004){this._year=newValue;this.edition+=newValue-2004; }
}
});
book.year=2005;
book.edition     //2

_year前面的下划线是一种常见的记号,用于表示只能通过对象方法访问的属性。访问器属性year包含一个getter函数和一个setter函数。

把year属性修改为2005会导致_year变成2005,而edition变为2。这是访问器属性的常见方式,即设置一个属性的值UI导致其他属性发生变化。

复杂点的用法:

$age,这样一个特殊的key表示这个key我不想暴露到外面。

isNaN(x)如果x是特殊的非数字值(或者能被转换为非数字值)返回true。

如果把 NaN 与任何值(包括其自身)相比得到的结果均是 false,所以要判断某个值是否是 NaN,不能使用 == 或 === 运算符。正因为如此,isNaN() 函数是必需的。

var man = {weibo: '@Bosn',$age: null,get age() {if (this.$age == undefined) { //undefined或者nullreturn new Date().getFullYear() - 1988;} else {return this.$age;}},set age(val) {val = +val; //把val强制转化为数字,如果val是数字声明都不做,如果是字符串转化为数字if (!isNaN(val) && val > 0 && val < 150) {this.$age = +val;} else {throw new Error('Incorrect val = ' + val);}}}console.log(man.age); //29man.age = 100;console.log(man.age); //100man.age = 'abc'; //error:Incorrect val =NaN

2、get/set与原型链

get ,set方法在和原型链结合的时候有一些更复杂的情况。

    function foo(){}Object.defineProperty(foo.prototype,'z',{get:function(){return 1;}});var obj=new foo();console.log(obj.z);      //1obj.z=10;console.log(obj.z);     //still 1

当obj对象上没有z属性的时候,并且在原型链上查找的时候发现有get方法或者set方法的时候,那么当我们尝试去赋值的时候,会尝试走get,stet方法,而不会再去给obj添加先属性这样处理。

如何实现对z的修改呢?

如何在obj上添加一个z属性呢?

通过Object.defineProperty

function foo() {}
Object.defineProperty(foo.prototype, 'z', {get: function() {return 1;}
});var obj = new foo();console.log(obj.z); //1
obj.z = 10;
console.log(obj.z); //still 1
Object.defineProperty(obj, 'z', {value: 100,configurable: true
});
console.log(obj.z); //100
delete obj.z;
console.log(obj.z); //back to 1

访问对象原型链上writable为false的属性时也是不可写的,此时也需要用Object.defineProperty来添加属性,如下:

var o={};
Object.defineProperty(o,'x',{value:1}); //writable=false,configurable=false
var obj=Object.create(o);
console.log(obj.x);//1
obj.x=200;
console.log(obj.x);//still 1,can't change it

Object.defineProperty(obj,'x',{writable:true,configurable:true,value:100});
console.log(obj.x);//100
obj.x=500;
console.log(obj.x);//500

3、getter,setter在项目中应用 【20181115】

export class LoginComponent implements OnInit{get isAutoLogin(){return this.loginService.supportAutoLogin();}set isAutoLogin(val){throw new Error('isAutoLogin can\'t be set to'+val);}
}

在模版中可以直接用

<div *ngIf = 'isAutoLogin'><p>Loading auto login credentials...</p>
</div>

好处,在template中*ngIf判断时候可以直接用属性,保证风格统一。

在代码中不用单独去维护一个变量。

五、属性标签

属性级的权限设置,有4个描述其属性行为的特性:【update20170320】

  • [[Configurable]]:表示能否通过delete删除属性从而重新定义属性,能否修改属性的特性,或者能否把属性修改为访问器属性。
  • [[Enumerable]]:表示能否通过for-in循环返回属性。
  • [[Writable]]:表示能否修改属性的值。
  • [[Value]]:包含属性的数据值。默认undefined。

1、怎样看一个对象的属性标签

用Object.getOwnPropertyDescriptor()第一个参数是你要判断的对象,第二个参数是一个字符串的属性名。

返回值是一个对象,如果是访问器属性,这个对象的属性有configurable,enumerable,get和set;如果是数据属性,这个对象的属性有configurable,enumerable,writable和value。

查看随便一个字面量对象的属性标签。

例子:

//console
var book={};
Object.defineProperties(book,{_year:{value:2004},edition:{value:1},year:{get:function(){return this._year;},set:function(newValue){if(newValue>2004){this._year=newValue;this.edition+=newValue-2004;}}}
});
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
descriptor
//Object {value: 2004, writable: false, enumerable: false, configurable: false}
var descriptor2=Object.getOwnPropertyDescriptor(book,"year");
//descriptor2
Object {enumerable: false, configurable: false}
//descriptor2.get
function (){return this._year;}

对于属性_year,value等于最初的值,configurable是false,而get等于undefined。

对于访问器属性year,value等于undefined,enumerable是false,而get是一个指向getter函数的指针。

在JavaScript中可以针对任何对象—包括DOM和BOM对象,使用Object.getOwnPropertyDescriptor()方法。

2、设置一个对象的属性标签

Object.defineProperty接收3个参数,第一个参数是添加属性的对象,第二个参数是字符串的属性的名字,第三个参数是个对象,这个对象里面就是具体的每一个标签的值

定义一个属性type的enumerable为false,所以for in时不可枚举,此外也可以通过Object.keys(person)来获取对象上的所有的key

给person定义多个属性

定义多个属性用Object.defineProperties,该方法接收2个参数,第一参数是你要定义属性的对象,第二个是一个复杂的对象,该对象第一级是你想定义的对象的属性,如下是title,corp和salary,属性的值等价于defineProperty里的第三个参数,即包含所有表情情况的一个对象。

下面定义属性时,标签为true的写了,不写的默认都是false。

更复杂的情况:

用标签属性访问,可以实现很多强大的功能,在编写一些复杂的程序上,帮助也是非常大的。

var person={};
Object.defineProperties(person,{title:{value:'fe',enumerable:true},corp:{value:'BABA',enumerable:true},salary:{value:50000,enumerable:true,writable:true},luck:{get:function(){return Math.random()>0.5?'good':'bad';}},promote:{set:function(level){this.salary*=1+level*0.1;}}
});console.log(person.salary); //50000
person.promote=2;
console.log(person.salary); //60000

属性的标签可以通过Object.defineProperty重复设置。

如果writable为false,不能修改属性的值,如果此时configurable为true,可以通过Object.defineProperty设置value来修改。或者把writable改为true,再修改属性值。所以configurable为true时想通过writable阻止属性的修改没有意义。

注意:

configurable为false不允许delete,不允许修改getter/setter方法,只允许把writable从true修改为false。【update20170320】

也就是说一旦把属性定义为不可配置的,就不能再把它变回克配置了,此时,再调用Object.defineProperty()方法修改除writable之外的特性,都会报错。

可以多次调用Object.defineProperty()方法修改同一个属性,但在把configurable特性设置为false之后就会有限制了。

六、对象标签、对象序列化

1、[[proto]]

原型链

2、[[class]]

[[class]]标签没有一个直接的方式去查看它或者是修改它。

可以间接的通过Object.prototype.toString的方式去获取class

Object.prototype.toString.call([1,2]);
//[object Array]

访问Object.prototype.toString返回的是[object 类型],用Object.prototype.toString.call(o).slice(8,-1);截取从第8个字符开始一直到最后,然后再去掉最后一个字符的字符串,便于查看类型。

3、[[extensible]]

[[extensible]]标签表示对象是否可扩展。

就是说对象上的属性是否可以被继续添加。

用Object.isExtensible(obj)来判断对象是否可扩展

var obj={x:1,y:2}
Object.isExtensible(obj)
//true       默认都是true

怎样不让扩展?

var obj={x:1,y:2}
Object.isExtensible(obj)
//true
Object.preventExtensions(obj)
Object.isExtensible(obj)
//false

不让扩展的后的目的或者结果:

obj.z=1;
obj.z
//undefined      //添加新属性失败
Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: true, enumerable: true, configurable: true}
//通过preventExtensions来阻止对象去添加新的属性 对象上的属性标签没变化

意味着属性仍然是可以删除掉 修改和枚举的。

往往我们在去阻止一个对象扩展的时候,我们不想让他们去修改属性标签,也不想让他们删除这些属性。

这个时候我们会用Object.seal方法,在Object.preventExtensions基础上又增加了一条限制,就是会把对象上的所有属性的configurable设置为false,所以我们再去查看属性标签,发现不同的是configurable变成了false。

Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: true, enumerable: true, configurable: true}
Object.seal(obj)
Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: true, enumerable: true, configurable: false}

可以通过Object.isSealed方法来判断一个对象是否被隐藏。

Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: true, enumerable: true, configurable: false}
Object.isSealed(obj)
//true

有的时候,我们想限制更强一点,让对象不仅不可以添加新属性,不可以配置属性标签,不可删除,甚至也不可写。我们可以用Object.freeze(obj)这样一个方法。

Object.freeze(obj)
Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: false, enumerable: true, configurable: false}

freeze之后configurable和writable都变成了false,这样就实现了不可写,不可改,不可添加属性,不可删除属性,不可修改属性的值这样一个目的。

可以通过Object.isFrozen(obj)判断对象是否被冻结

Object.freeze(obj)
Object.getOwnPropertyDescriptor(obj,'x')
//Object {value: 1, writable: false, enumerable: true, configurable: false}
Object.isFrozen(obj);
//true

 注意:no affects prototype chain!!!

这里所有的方法只是针对这样一个对象的,并不会影响对象的原型链。

所以如果想对你的原型链也做一些处理的话。可以拿到对象的原型,遍历原型链层层冻结。

4、序列化

前端javascript处理结果发到后端,后端需要接收一字符串的数据格式。

用JSON.stringify(obj)做处理。

序列化的

  • 如果值是undefined,整个属性就不会出现在序列化的结果当中。
  • 如果属性值是NaN或者是Infinity的话,那么会转化为null
  • 如果是时间的话会转化为UTC的实际格式

后端返回JSON数据,怎样把它变成javascript对象?

合法的JSON属性必须以双引号引起来。

obj=JSON.parse('{"x":1}')
obj.x
//1

有的时候序列化会更复杂一点,可以自定义序列化

如何定制序列化的过程?

obj对象的o属性的值是个对象,o的对象序列化结果想要自定义。只需要在当前层下写一个toJSON方法,该方法的this指向当前层级o。

var obj={x:1,y:2,o:{o1:1,o2:2,toJSON:function (){return this.o1+this.o2;}}
}
JSON.stringify(obj)
//"{"x":1,"y":2,"o":3}"

再去stringfify时o就是通过toJSON方法返回的。

5、其他对象方法

1、toString()

var obj={x:1,y:2}
obj.toString()
//"[object Object]"

调用对象的toString()默认会返回[object Object],没什么用,我们可以自定义toString方法。

obj.toString=function(){return this.x+this.y}
obj.toString()
//3

字符串拼接时,对象调用toString,用一元运算符+尝试把对象转化为数字,也会调用toString。

2、valueOf()

尝试把对象转换为基本类型时会自动去调valueOf。

用一元+尝试把对象转化为数字,返回的结果是103,是从valueOf来的。

注意:

当valueOf和toString都存在的时候,不管是一元的加号(+)还是二元的作为字符串拼接的的加号(+),在做具体操作的时候都会尝试把对象转化为基本类型。

会先去找valueOf,如果valueOf返回的是基本类型的话,就以valueOf的值作为结果,反之如果valueOf不存在或者返回的是对象这样一个不合法的值,就会去找toString。如果toString和valueOf都没有,或者都返回了对象,那么就会报错。

toString和valueOf一般都是做操作时,js解释器自动去调用的方法。
参考:http://www.cnblogs.com/wangfupeng1988/tag/%E5%8E%9F%E5%9E%8B/

本文作者starof,因知识本身在变化,作者也在不断学习成长,文章内容也不定时更新,为避免误导读者,方便追根溯源,请诸位转载注明出处:http://www.cnblogs.com/starof/p/4904929.html有问题欢迎与我讨论,共同进步。

转载于:https://www.cnblogs.com/starof/p/6374762.html

javascript 对象(四)相关推荐

  1. JavaScript基础——第四章,JavaScript对象及初识面向对象

    文章目录 JavaScript对象及初识面向对象 1.对象 1.1 对象的概念 1.2 内置对象 1.3 自定义对象 1.3.1 操作符new创建对象 1.3.2 使用字面量赋值的方式定义对象 2.构 ...

  2. 我对javascript对象的理解

    前言 JavaScript这门语言除了基本类型都是对象,可以说JavaScript核心就是对象,因此理解JavaScript对象及其种种特性至关重要,这是内功.本文介绍了我对es5对象,原型, 原型链 ...

  3. 在js中加html_在HTML文档中嵌入JavaScript的四种方法

    在HTML里嵌入JavaScript 在HTML文档里嵌入客户端JavaScript代码有4中方法: 1.内嵌,放置在标签之间  (少): 2.放置在有 3.放置自HTML事件处理程序中,该事件处理程 ...

  4. 通过属性值从对象数组中获取JavaScript对象[重复]

    本文翻译自:Get JavaScript object from array of objects by value of property [duplicate] This question alr ...

  5. 重学前端-学习笔记-JavaScript对象

    说明 重学前端是程劭非(winter)在极客时间开的一个专栏,在此主要整理我的学习笔记.如有侵权,请联系我,谢谢. javascript对象特征 对象具有唯一标识性:完全相同的两个对象,也不是同一个对 ...

  6. 如何判断Javascript对象是否存在

    Javascript语言的设计不够严谨,很多地方一不小心就会出错. 举例来说,请考虑以下情况. 现在,我们要判断一个全局对象myObj是否存在,如果不存在,就对它进行声明.用自然语言描述的算法如下: ...

  7. JavaScript 对象所有API解析【2020版】

    写于 2017年08月20日,虽然是2017年写的文章,但现在即将2020年依旧不过时,现在补充了2019年新增的ES10 Object.fromEntries().发到公众号申明原创.若川顺便在此提 ...

  8. javascript对象包含哪些要素_让人迷糊的JavaScript对象(Object一)

    对于很多初学的小伙伴听到JavaScript内置对象.BOM.DOM.WEB API等关键词基本上都是迷糊,不是很明白他们之间的关系,以及他们是如果建立联系的.虽然我们现在小伙伴在学VUE,React ...

  9. javascript小技巧JavaScript[对象.属性]集锦

    如果你找的javascript的东西的话,建议你 ctrl+F  直接在这个页上找,因为这里80%有你要找的,但是要让你挨着看的话,你就准备看完就去配眼镜!! 事件源对象 event.srcEleme ...

  10. JavaScript(三)—— JavaScript 函数/JavaScript 作用域/JavaScript 预解析/JavaScript 对象

    本篇为 JavaScript 系列笔记第三篇,将陆续更新 JavaScript(一)-- 初识JavaScript/注释/输入输出语句/变量/数据类型 JavaScript(二)-- JavaScri ...

最新文章

  1. MySQL基本了解与使用
  2. 正经聊一聊脑机接口的发展现状|脑科学开放日
  3. 世界农业趋势-国际农民丰收节贸易会: 新技术谋定生产过程
  4. 为什么要使用Entity Framework
  5. React Native之Props(属性)和State(状态)和简单样式简单使用
  6. Sqli-labs less 64
  7. 巨蟒python全栈开发flask5
  8. 算法总结 -- 博弈论(PN图)
  9. 【C语言】数据结构C语言版 实验5 递归
  10. Transformers Assemble(PART V)
  11. linxu 获取指定字符的前后多少行
  12. 保护眼睛——设置WIN7和XP 窗体、Chrome、IE网页背景颜色(zz)
  13. Mini-USB接口的引脚定义与USB与miniUSB接口区别
  14. 黄灯:一个农村儿媳眼中的乡村图景
  15. 使用Java读写dbf文件【附源代码】
  16. js中求2个数的最大值的几种方法
  17. appcrash事件怎么解决?三种方法教你
  18. 什么是TMD格式?TDM格式详细介绍
  19. layui单元格编辑监听
  20. 【JZOJ 4598】准备食物

热门文章

  1. python纸牌游戏_《升级》扑克牌游戏——Python实现
  2. cron一点半到两点半之间每分钟_分辨率,定位精度,重复定位精度三者之间有什么关系?...
  3. java权限精确到按钮_搞定权限设计1-页面按钮控制(精确到某个用户和某个按钮)...
  4. layui列表筛选列_layui框架的table字段筛选功能介绍
  5. 【数据结构(C语言)】数据结构-树
  6. kafka性能优化入门
  7. git status命令
  8. kafka 查看消费者组
  9. 再论DataSet与DataFrame的区别
  10. 浏览器异步加载和同源策略