JavaScript对象学习

对象是JavaScript的基本数据类型。对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。

对象也可看做是属性的无序集合,每个属性都是一个名/值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。

然而对象不仅仅是字符串到值的映射,除了可以保持自有的属性,JavaScript对象还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性。这种“原型式继承”(prototypal inheritance)是JavaScript的核心特征。JavaScript对象是动态的—可以新增属性也可以删除属性。有时它们也用做字符串的集合(忽略名/值对中的值)。除了字符串、数字、true. false. null和undefined之外,JavaScript中的值都是对象。

对象的创建

最简单的方式就是在JavaScript代码中使用对象直接量

对象直接量是由若干名/值对组成的映射表,名/值对中间用冒号分隔,名/值对之间用逗号分隔,整个映射表用花括号括起来。

 

    var empty ={};                  //没有任何属性的对象
    var point={x:0, y:0};          //两个属性的对象
    var point2 ={x:point.x, y:point.y+1};             // 复杂的值
    var book={       
        "main title":"7ava5cript",             //属性名字里有空格,必须用字符串表示
        'sub-title':"The Definitive Guide",      //属性名字里有连字符,必须用字符串表示
        "for":"all audiences",              // "for"保留字,因此必须用引号
        "for":"vvvaaaddd",              // 同名"for" 属性是没有意义的,后者会覆盖前者
        author:{                              //这个属性的值是一个对象
        firstname: "David",
        surname: "Flanagan"                   //注意,这里的属性名都没有引号
        }
    };

通过new创建对象

new运算符创建并初始化一个新对象

关键字new后跟随一个函数调用。这里的函数称做构造函数(constructor),构造函数用以初始化一个新创建的对象。JavaScript语言核心中的原始类型都包含内置构造函数。

var o =new Object();          //创建一个空对象,和{}一样
var a = new Array();              //创建一个空数组,和[]一样
var d = new Date();             //创建一个表示当前时间的Date对象

通过Object.create()创建对象
在使用这个方法前,我们要学习下javascript中的原型,每一个JavaScript对象都和另一个对象相关联。每一个对象都从原型继承属性。

所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JavaScript代码Object.prototype获得对原型对象的引用。同使用{}创建对象一样,通过newObject()创建的对象也继承自Object.prototype。

没有原型的对象为数不多,Object.prototype就是其中之一。它不继承任何属性。其他原型对象都是普通对象,普通对象都具有原型。所有的内置构造函数(以及大部分自定义的构造函数)都具有一个继承自Object.prototype的原型。例如,Date.prototype的属性继承自Object.prototype,因此由new Date()创建的Date对象的属性同时继承自
Date.prototype和Object.prototype。这一系列链接的原型对象就是所谓的“原型链”

创建一个新对象可以通过Object.create(),其中第一个参数是这个对象的原型。

Object.create()是一个静态函数,而不是提供给某个对象调用的方法。使用它的方法很简单,只须传入所需的原型对象即可:

var o1 = Object.create({x:1, y:2});//01继承了属性x和Y

如果想创建一个普通的空对象(比如通过{}或new Object()创建的对象),需要传入Object.prototype
var o3=Object.create(Object.prototype);   //03和{}和new Object()一样

var o= {}  //0从Object.prototype继承对象的方法,Object.prototype作为它们的原型。

假设要查询对象属性X,如果不存在X,那么将会继续在原型对象中查询属性x。如果原型对象中也没有X,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行查询,直到找到X为止。可以看到,对象的原型属性构成了一个“链”,通过这个“链”可以实现属性的继承

获得属性和设置属性

可以通过点(.)或方括号([])运算符来获取、更改属性的值。

var author=book.author;     //三种方式都是可以获取到属性的
var name=author.surname
var title=book["main title"]
book.author = 'xinde a';         //两种都可以设置值
book["for"] = 'hehehe';          //如果是JavaScript的保留字,那么必须用方括号[]更改

属性访问错误(不存在的)

访问对象一个不存在的属性会返回一个undefined(未定义)

var book = {};
book.subtitle;    //undefined:属性不存在
var j = c.x;         //对象都不存在,会报错  =>  ReferenceError: c is not defined
但是,如果对象不存在,那么试图查询这个不存在的对象的属性就会报错。

遍历属性

可以使用for/in来遍历对象,从而获得所有属性,ECMAScript 5还多加了两种遍历方法

var kk = {x:1,y:2,z:3};
for(var name in kk){document.write(name);document.write('   ' + kk[name] + "<br />")}
//上面就是用for/in,5还多加了两个定义了两个用以枚举属性名称的函数。
var c = Object.keys(kk);     //返回一个数组,由对象中可枚举的自有属性的名称(x,y,z)组成
var d = Object.getOwnPropertyNames(kk) //和上面的方法类似,只是它返回对象的所有自有属性的名称,不仅仅是可枚举类型

删除属性

delete运算符可以删除对象的属性。它的操作数应当是一个属性访问表达式。

delete book.author; //book不再有属性author
delete book["main title"]; //book也不再有属性”main title"
o = {x:i);        //有一个属性x,并继承属性toString
delete o.x;         //删除x,返回true
delete o.x;          //多次删除,什么都没做(x已经不存在了),返回true
delete o.toString;      //什么也没做(toString是继承来的),返回true
delete i;          //无意义,返回true
a=(p:(x:l)}; b=a.p; delete a.p;      //b.x  依然是1 ,因为引用还存在

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

检测属性

判断某个属性是否存在于某个对象中。可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法来完成这个工作,甚至仅通过属性查询也可以做到这一点。
除了使用in运算符之外,另一种更简便的方法是使用“!==”判断一个属性是否是undefined:
对象的hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性。对于继承属性它将返回false:

var o={x: 1}        
"x"  in o;        //true:  x是o的属性
"toString" in o;  //true: o继承toString属性   
o.x !== undefined;   //true:o中有属性x,可以通过这种方法判断如果
var o={x: undefined}    //则只能使用in方法,不能使用上面这个方法
o.hasOwnProperty("x")            //true:o有一个自有属性x
o.hasOwnProperty("toString")        //false: toString是继承属性

属性“设置器方法”和“访问器方法”(ECMAScript 5新增特性)

对象属性是由名字、值和一组特性,属性值可以用一个或两个方法替代,这两个方法就是getter和setter.
存取器属性定义为一个或两个和属性同名的函数,

var a =  {
		'hehe':123,
		get s1tring(){return this.hehe;	},
		set s1tring(c){this.hehe = c;},
		get hehe(){ }     //如果出现同名的存取器方法,则会抛出一个Uncaught RangeError: Maximum call stack size exceeded(堆栈溢出问题)
}
a.s1tring = "1512324"
alert(a.s1tring);    //输出1512324 

这个函数定义没有使用function关键字,而是使用get和(或)set,注意,这里没有使用冒号将属性名和函数体分隔开,这里是使用的逗号.

属性的特性

除了包含名字和值之外,属性还包含一些标识它们可写、可枚举和可配置的特性。
数据属性的4个特性分别是它的值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)。
为了实现属性特性的杳询和设置操作,ECMAScrint 5中定义了一个名为“属性描述符”的对象,这个对象代表4个特性。
描述符对象的属性和它们所描述的属性特性是同名的,其中veritable. enumerable和configurable都是布尔值,通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符。

var he = Object.getOwnPropertyDescriptor({x:20},'x');   //返回的是一个对象
he //这个对象包涵了4个属性 {value: 20, writable:true, enumerable:true, configurable:true} 其实这个对象是这样的
for(var k in he){	document.write(k + "  :" +he[k]+"   ,");	}  //可以用for来验证一下
设置属性的特性

想让新建属性具有某种特性,则需要调用Object.definePeoperty().
传人要修改的对象、要创建或修改的属性的名称以及属性描述符对象:

var kk ={};
Object.defineProperty(kk,"x",{
			value:1,
  			writable: true,
  			enumerable: false,
  			configuratrle: true
		});             //通过这个方法我们可以配置一个不可枚举的属性x
alert(kk.x);            //有正确输出x,但使用for/in循环不可枚举

Object.defineProperty(o, "x",{veritable: false})    //  更改为只读属性

可以看到,传入Object.defineProperty()的属性描述符对象不必包含所有4个特性。
如果要同时修改或创建多个属性,则需要使用Object.defineProperties()

Object.defineProperties(对象,映射表);      //用映射表表达多个赋值
Object.defineProperties({},{
x :{ value: 1, writable: true, enumerable true, configurable:true},
y :{ value: 1, writable: true, enumerable true, configurable:true}
}

对象的三个属性

对象还拥有三个相关的对象特性(object attribute):

  • 对象的原型(prototype)指向另外一个对象,本对象的属性继承自它的原型对象。
  • 对象的类(class)是一个标识对象类型的字符串。
  • 对象的扩展标记(extensible flag)指明了(在ECMAScript 5中)是否可以向该对象添加新属性。

对象的原型属性是用来继承属性的,是在实例对象创建之初就设置好的。在ECMAScript 5中,将对象作为参数传入Object.getPrototype0f()可以查询它的原型
要想检测一个对象是否是另一个对象的原型,可以使用isPrototype0f()方法,

var p = {x:1};        
var o=Object.create(p);              //使用这个原型创建一个对象
p.isPrototype0f(o);           //true:o继承自P
Object.prototype.isPrototype0f(o) // true:p继承自Object.prototype

类属性
对象的类属性(class attribute)是一个字符串,用以表示对象的类型信息。
默认的toString()方法(继承自Object.prototype)返回了如下这种格式的字符串:
[object Object]

可扩展性
对象的可扩展性用以表示是否可以给对象添加新属性。所有内置对象和自定义对象都是可扩展的
ECMAScript 5定义了用来查询和设置对象可扩展性的函数。通过将对象传人。Object.esExtensible(),来判断该对象是否是可扩展的。
如果想将对象转换为不可扩展的,需要调用Object.preventExtensions(),将待转换的对象作为参数传进去。注意,一旦将对象转换为不可扩展的,就无法再将其转换回可扩展的了。
Object.seal()和Object.preventExtensions()类似,除了能够将对象设置为不可扩展的,还可以将对象的所有自有属性都设置为不可配置的。对于这些封闭起来的对象,可以使用Object.isSealed()来检测对象是否封闭。
Object.freeze():更严格的锁定对象(冻结)。和seal类似,不过它还会将自有的所有数据属性设为只读(如果对象的存储器有setter方法,该属性不会被影响,也就是说可以通过给属性赋值调用它们)。
通过Object.isFrozen()检测对象是否冻结。

序列化对象

对象序列化(serialization)是指将对象的状态转换为字符串,也可将字符串还原为对象。ECMAScript 5提供了内置函数JSON.stringify()和JSON.parse()用来序列化和还原JavaScript对象。这些方法都使用JSON作为数据交换格式,JSON的全称是“JavaScriptObject Notation”— JavaScript对象表示法,它的语法和JavaScript对象与数组直接量的语法非常相近:

hehe={x:1, y:{z:[false,null,""]}};      //定义一个测试对象
var s=JSON.stringify(hehe);       //s输出是这个样子的  {"x":1,"y":{"z":[false,null,""]}}
var P=JSON.parse(s);          //P是o的深拷贝

JSON的语法是JavaScript语法的子集,JSON.parse()依然保留它们的字符串形态
JSON.stringify()只能序列化对象可枚举的自有属性,否则在序列化后的输出字符串中会将这个属性省略掉。

对象方法

JavaScript对象都从Object.prototype继承属性,以下是Object.prototype的方法
toString() : 没有参数,它将返回一个表示调用这个方法的对象值的字符串。 希望使用字符串都会调用toString()方法
toLocaleString() :返回一个表示这个对象的本地化字符串。
toJSON():Object.prototype实际上没有定义toJSON()方法,JSON.stringify()方法会调用toJsoN()方法。
valueOf():将对象转换为原始值而非字符串的时候才会调用它

发表评论

发表评论

*

沙发空缺中,还不快抢~