JavaScript之对象

来源:互联网 发布:国泰君安快期交易软件 编辑:程序博客网 时间:2024/05/01 18:54

概述


除了字符串、数字、undefined、null、布尔值外,JavaScript中的值全是对象。

每个属性都有属性特性:
  • 可写 ,表明是否可以设置该属性的值
  • 可枚举,表明是否可以通过for/in循环返回该属性
  • 可配置,表明是否可以删除或修改该属性
每个对象除了属性之外,还有三个相关的对象特性:
  • 对象的原型(prototype)指向另一个对象,本对象的属性继承自它的原型对象
  • 对象的类(class)是一个标识对象类型的字符串
  • 对象的扩展标记(extensible flag)指明了是否可以向该对象添加新属性

创建对象

当属性名中有空格,连字符等需要用字符串表示

对象直接量是一个表达式,这个表达式的每次运算都创建并初始化一个新的对象。每次计算对象直接量的时候,也都会计算它的每个属性的值。也就是说,如果在一个重复调用的函数循环体内使用了对象直接量,它将创建很多新对象,并且每次创建的对象的属性值也有可能不同。

所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JavaScript代码Object.prototype获得对原型对象的引用。

没有原型的对象位数不多,Object.prototype就是其中之一。它不继承任何属性,其它原型对象都是普通对象,普通对象都具有原型。所有的内置构造函数(以及大部分自定义的构造函数)都具有一个继承自Object.prototype的原型

ES5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型,Object.create()提供第二个可选参数,用以对对象的属性进行进一步的描述。
Object.create()是一个静态函数,而不是提供给某个对象调用的方法.
var 0 =Object.create({x:1 ,y:2});

可以通过传入参数null来创建一个没有原型的新对象,但通过这种方式创建的对象不会继承任何东西,甚至不包含基础方法,比如toString()

如果向创建一个普通的空对象(比如{}或new Object()创建的对象),需要传入Object.prototype:
var o3 = Object.create(Object.prototype)//等同于new Object() 和{}

 如果给继承对象的属性赋值,则这些属性只会影响这个继承对象自身,而不是原始对象。

属性的查询和设置

对于点(.)来说,右侧必须是一个以属性名称命名的简单标识符。对于方括号来说([]),方括号内必须是一个计算结果为字符串的表达式,这个字符串就是属性的名字。

ES5允许在点运算符后面直接使用保留字。

当使用方括号时,我们说方括号内的表达式必须返回字符串。其实更严格地讲,表达式必须返回字符串或返回一个可以转换为字符串的值。

JavaScript对象都是关联数组。

当通过点运算符(.)访问对象的属性时,属性名用一个标识符来表示。标识符必须直接出现在JavaScript程序中,它们表示数据类型,因此程序无法动态修改。而[]则可以
var addr = ""for(i =0;i>4;i++){  addr+=customer["address"+i]+'\n'}

现在假设给对象o的属性x赋值,如果o中已有属性x(非继承),那么这个赋值操作只改变这个已有属性x的值。如果o中不存在属性x,那么赋值操作给o添加一个新属性x。如果之前o继承自属性x,那么这个继承的属性就被新创建的同名属性覆盖。

在JavaScript中,只有在查询属性时才会体会到继承的存在,而设置属性则和继承无关,这是JavaScript的一个重要特性,该特性可以让程序员有选择地覆盖继承的属性。

属性赋值操作首先检查原型链,以此判定是否允许赋值操作。如果继承自一个只读属性x,那么赋值操作是不允许的。

属性赋值要么失败,要么创建一个属性,要么在原始对象中设置属性。(?P126)

查询一个不存在但属性并不会保存。
如果对象不存在,那么试图查询这个不存在的对象的属性就会报错。null和undefined值都没有属性,因此查询这些值的属性会报错。
var len = book && book.subtitle && book.subtitle.length

在严格模式下,任何失败的属性这只操作都会抛出一个类型错误异常。
在以下场景给对象o设置属性p会失败
  • o中的属性p是只读的:不能给只读属性重新赋值(defineProperty()方法中有例外,可以对可配置的只读属性重新赋值)
  • o中的属性p是继承属性,且他是只读的:不能通过同名自有属性覆盖只读的继承属性
  • o中不存在自有属性p:o没有使用setter方法继承属性p,并且o的可扩展性是false。如果o中不存在p,且没有setter方法可供条约,则p一定会添加至o中。但如果o不是可扩展的,那么在o中就不能定义新属性


删除属性

delete指数断开属性和宿主对象但联系,而不会去操作属性中的属性。因此只在销毁对象的时候,要遍历属性中的属性,依次删除

delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除,而且这会影响到所有继承自这个原型的对象)

delete不能删除那些可配置性为false的属性(尽管可以删除不可扩展对象的可配置属性)。严格模式下,删除一个不可配置属性会报一个类型错误。

在严格模式下,delete后跟随一个非法的操作数(比如x),则会报一个语法错误,因此必须显式指定对象及其属性


检测属性

in用于检查对象是否具有某个属性(自有和继承),in可以分辨属性不存在和属性为undefined
对象的hasOwnProperty()方法用来检测给的的名字是否是对象的自有属性,对于继承属性会返回false
propertyIsEnumerable()是hasOwnPeoperty()的增强版,只有检测到该自有属性的可枚举性为true时他才返回true


枚举属性

Object.getOwnPropertyNames()和Object.keys()类似,指数它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性。


属性getter和setter

当程序查询存取器属性的值时,JavaScript调用getter方法(无参数)。这个方法的返回值就是属性存在表达式的值。当程序这种一哦过存取器属性的值时,JavaScript调用setter方法,将赋值表达式右侧的值当作参数传入setter。从这种意义上讲,这个方法赋值设置属性值。可以忽略setter方法的返回值。

与数据属性不同,存取器属性不具有可写性。如果属性同时具有getter和setter方法,那么它是一个读/写属性。如果只有一个getter方法,那么是只读属性。如果只有setter方法,那即是只写属性。读取只写属性总是返回undefined

和数据属性已有,存取器属性是可以继承的


属性的特性

存取器属性不具有值(value)特性和可写性,它们的可写性是由setter方法存在与否决定的。因此存取器属性的4个特性是独缺、写入、可枚举性和可配置性。

为了实现属性的描述对象的属性有value、writable、enumerable和configurable。存取器属性的描述性对象则用
get属性和set属性代替value和writable。其中writable、enumerable和configurable都是布尔值。get和set属性是函数值

Object
var o={x:1}Object.getOwnPropertyDescriptor(o,"x")//Object {value: 1, writable: true, enumerable: true, configurable: true}

Object.getOwnPropertyDescriptor()只能获得自有属性的描述符

要想设置属性的特性,或者想让新建属性具有某种特性,需要调用Object.defineProperty(),传入修改的对象,要创建或修改的属性名称以及属性描述符对象
Object.defineProperty(o,"x",{value:2,enumerable:false})      //Object {x: 2}o.x  //2Object.keys(o)   //[]

传入Object.defineProperty()的属性描述符对象不必包含所有4个特性。对于新创建的属性来说,默认的特性值是false或undefined。对于修改已有的属性,则默认不做任何改变。注意,该方法要么是修改已有属性有么新建自有属性,不能修改继承属性

如果要同时修改或创建多个属性,则需要使用Object.defineProperties()。第一个参数是要修改的对象,第二个参数则是一张映射表,要包含新建或修改的属性的名称,以及它们的属性描述符
var p = Object.defineProperties({},{    x:{value:1,writable:true,enumerable:true,configurable:true},  y:{value:1,wtitable:false},  r:{   get: function(){return Math.sqrt(this.x*this.x+this.y*this.y)}}})

Object.defineProperties()会返回修改后的对象(Object.defineProperty()一样)

对于那些不允许创建或修改的属性来说,如果用defineProperty对其操作(新建或修改),会抛出类型错误异常
P137

对象的三个属性

原型属性是在实例对象创建之初就设置好的,通过对象直接量创建的对象使用Obejct.prototype作为它们的原型。通过new创建的对象使用构造函数的prototype属性作为她的原型。通过Obejct.create()创建的对象的使用第一个参数(也可以是null)作为它们的原型


在ES5中,将对象作为参数传入Obejct.getPrototypeOf()可以查询它的原型。ES3中可以用o.constructor.prototype来检测对象原型,但这种方法并不可靠——对于对象直接量有效,但对于通过Object.create()创建的对象则往往不是这样


检测一个对象是否是另一个对象的原型(或处于原型链),可以使用isPrototypeOf()方法.比如p.isPrototypeOf(o)可以检测p是不是o的原型


要想获得对象的类,可以调用对象的toString()方法,然后提取已返回字符串的第8个到倒数第二个位置直接到字符(由于很多对象重写toString,因此应该采用call)

Object.prototype.toString(0).slice(8,-1)


通过内置构造函数创建的对象包含类属性,它与构造函数名称相匹配。宿主对象也包括有意义的类属性,但着依赖于具体的js实现。自定义构造函数创建的对象的类属性是Object,而对象直接量和Object.create()也是如此


对象的可扩展性用于表示是否可以给对象添加新对象。在ES5中,所有的内置对象和自定义对象都是可扩展的,除非手动转化


Object.preventExtensions()可以将对象转化为不可扩展,而不可扩展无法变为可扩展。而Object.isExtensible()则用来判断。此外,如果给一个不可扩展的对象的原型添加属性,这个不可扩展的对象统一会继承这些新属性


Object.seal()个Object.preventExtensions()类似,除了能够将对象设置为不可扩展的,还可以将对象的所欲呕自有属性都设置为不可配置的。

对于那些已封闭起来的对象是不可解封的。可以用Object.isSealed()来检测对象是否封闭

Object.freeze()则更严格,除了将对象设置为不可扩展和将属性配置为不可配置,还会将所有属性设置为只读。setter不受影响

Object.isFrozen()用于检测


序列化对象

ES5内置了JSOO.stringify()和JSON.parse()用来序列号和还原js对象。

JSON支持对象、数组、字符串、无穷大数字、布尔值和null的序列号和还原。(日期会变为字符串)



对象方法

Object中默认的toLocaleString()方法并不作任何本地化操作,只是调用toString()方法并返回对应值。Date()和Number()的toLocaleString()方法做了定制,而Array会对每一个元素都调用toLocaleString()


对于需要执行序列化的对象来说,JSON.stringify()方法会调用toJSON()方法。若待序列化的对象存在该方法,则调用,返回值即是序列化的结果,而不是原始对象









0 0
原创粉丝点击