JavaScript 对象

对象是js的基本数据类型。

对象是一种复合值:它将很多值 聚合在一起,可通过名字访问这些值 。

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

JS对象还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性。

对象最常见的用法是创建create,设置set,查找query,删除delete,检测test ,枚举 enumerate

属性包括名字和值。

对象除了包含属性外,每个对象还拥有三个相关的对象特性:

      对象的原型

      对象的类

      对象的扩展标记

 

三类JS对象和两类属性:

内置对象: 规范定义的对象或类。比如 数组,函数,日期和正则表达式

宿主对象:  由JS解释器(如浏览器)所嵌入的宿主环境定义的。

自定义对象: 运行JS中代码创建的对象

自有属性: 是直接在对象中定义的属性

继承属性: 是在对象的原型中定义的属性

 

创建对象

可以通过对象直接量、关键字new 和 Object.create()函数来创建对象。

对象直接量

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

var empty = {}; //没有任何属性
var point = { x:0 , y:0 }; //两个属性
var point2 = { x:point.x, x.point.y + 1}; //更复杂的值

var book = {
	"main title" : "Javascript", ,//属性名字里有空格,必须用字符串表示 
	'sub-title' : "The ... ", //属性名字里有连字符,必须用字符串表示
	"for": "all ..." , //"for"是保留字,因此必须用引号
	author: {//这个属性值是一个对象
		firstName: "Jin", //这里的属性名都没有引号
		surName: "He"
	}
}

通过new创建对象

new运算符创建并初始化一个新对象。关键字new后跟随一个函数调用。

这里的函数称为构造函数(constructor),构造函数用以初始化一个新创建的对象。例如:

var o = new Object(); //创建一个空对象,和 {}一样
var a = new Array(); //创建一个空数组,和[]一样
var d = new Date(); //创建一个表示当前时间的Date对象
var r = new RegExp("js"); //创建一个可以进行模式匹配的RegExp对象

原型

每一个Js对象(ull除外)都和另一个对象相关联,‘另一个对象’就是我们要说的原型,每一个对象都从原型继承属性.

Object.prototype获得原型对象的引用。

通过new Object()创建的对象也是继承自Object.prototype.

通过new Array()创建的对象也是继承自Array.prototype.

通过new Date()创建的对象也是继承自Date.prototype.

所有的内置构造函数都具有一个继承自Object.prototype的原型。例如 Date.prototype的属性继承自Object.prototype.因此new Date()创建的Date对象的属性同时继承自Date.prototype和Object.prototype.这一系列链接的原型对象就是所谓的“原型链接”(prototype chain)

 

Object.creat()

该方法创建一个新对象,其中第一个参数是这个对象的原型。第二个是可选参数,用以对对象的属性进行进一步的描述。

Object.creat()是一个静态函数,而不是提供给某个对象调用的方法

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

可以通过传入参数null来创建一个没有原型的新对象。但这种方式创建的对象不会继承任何东西。

var o2 = Object.create(null) ; //o2不继承任何属性和方法

如果想创建一个普通的空对象,如通过{} 或 new Object() 创建的对象,需要传入Object.prototype:

var o3 = Object.create(Object.prototype); //o3和{}和new Object()一样

通过原型继承创建一个新对象:

//inherit()返回了一个继承自原型对象p的属性的新对象
//使用Object.create()
//如果 不存在Object.create(),则退化使用其他方法
function inherit(p) {
	
	if( p == null) throw TypeError(); //p是一个对象 ,但不能是Null
	if(Object.create) //如果Object.create 存在
	return Object.create(p) //直接使用它
	var t = typeof p; //否则进行进一步的检测
	if(t!=="object" && !=="function") throw TypeError();
	function f() {};//定义一个空构造函数
	f.prototype = p ; //将其原型属性设置为p
	return new f(); //使用f()创建p的继承对象
	
}

 

inherit() 它返回的新对象继承了参数对象的属性。

 

属性的查询和设置

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

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

var author = book.author; //得到book的"author"属性
var name = author.surname; //得到获得author的"surname"属性
var title = book["main title"] //得到book的"book title"属性

也可以通过这要的方式创建属性或是给属性赋值,但是放在左侧,如:

book.edition = 6; //给book创建一个名为"edition"的属性
book["main title"] = "Js"; //给 "main title"属性赋值

点运算符后的标识符不能是保留字,比如不能是 o.for,o.class

 

作为关联数组的对象

object.prototype;
object[prototype];

第二种,用方括号括起来,这个数组元素是通过字符串索引而不是数字索引,这种数组就是关联性数组,也称做散列,映射或字典。Javascript对象都是关联数组。

当通过[]来访问对象的属性时,属性名通过字符串来表示 。字符串是javascript的数据类型,在程序 运行时可以修改和创建它们。

var addr = "";
for(i = 0; i < 4 ; i++) {
    addr += customre["address" + i] + '\n';
    
}

//这段代码读取customer对象的address0,address1,address2,address3属性,并将他们连接起来
function addstock (portfolio, stockname, shares) {
	portfolio[stockname] = shares;
}

假设这个程序,利用网络计算当前用户股票市场投资的金额。程序允许用户输入每只股票的名称和购股份额。该程序使用protofolio的对象来存储这些信息。每只股票在这个对象中都有对应的属性,属性名称就是股票名称,属性值就是购股数量。例,如果用户持有IBM的50股,那就是portfolio.ibm属性的值 就是50。

由于用户在程序运行时输入的股票,因此无法得知这些股票是什么名称。因此不能用(.)来访问对象portfolio的属性,但可以使用[]。

下面例子利用for/in计算portfolio的总值:

function getvalue (portfolio) {
	var total = 0.0;
	for(stock in portfolio) {//遍历portfolio中的每只股票
		var shares = portfolio[stock]; //得到每只股票的份额
		var price = getquote(stock); //查找股票价格;
		total += shares * price; //将结果累加至total中
	}
	return total; //返回total的值
}

 

属性继承

Javascript对象具有 “自有属性” (own prototype),也有一些属性是从原型继承而来的。用inherit()函数传入指定原型对象来创建实例

var o = {}; //o从Object.prototype继承对象的方法
o.x = 1; //给o定义一个属性x
var p = inherit(o); //p继承o和Object.prototype
p.y = 2; //给这定义一个属性y
var q = inherit(p); //q继承p、o和Object.prototype
q.z = 3; //给q定义一个属性z
var s = q.toString(); //toString继承自Object.prototype
q.x + q.y ; //3.x和y分别继承自o和p

属性删除

delete运算符。

delete book.author; //book不再有属性author
delete book["main title"]; //book不再有属性'main title'

delete运算符只能删除自有属性,不能删除继承属性。

当delete表达式删除成功没有任何副作用,它返回true.如果delete后不是一个属性访问表达式,delete同样返回true:

o = { x:1 }; //o有一个属性x,并继承属性toString
delete o.x ; //删除x,返回true
delete o.x ; //什么都没有做(事实上x已经不存在了),返回true
delete o.toString; //什么也没做(toString是继承来的),返回true
delete 1; //无意义,返回true

检测属性

判断某个属性是否存在于某个对象中。可以通过 in运算符,hasOwnPreperty(),propertyIsEnumerable()。

in运算符 的左侧是属性名,右侧是对象。

var o = { x:1 };
"x" in o; //true:'x'是o的属性
"y" in o; //false: 'y'不是o的属性
"toString" in o; //true: o继承toString属性

对象的hasOwnProperty()方法用来检测给定的名字是否是对象的自有属性。对于继承属性它将返回false:

var o = { x:1 };
o.hasOwnProperty("x"); //true,o有一个自有属性x
o.hasOwnProperty("y"); //false,o不存在属性y
o.hasOwnProperty("toString"); //false,tostring是继承属性

propertyIsEnumerable()检测是自有属性且这个属性的可枚举性。

var o = inherit({ y:2 });
o.x = 1;
o.propertyIsEnumerable("x"); //true : o 有一个可枚举的自有属性x
o.propertyIsEnumerable("y"); //false : y是继承来的
Object.prototype.propertyIsEnumerable("toString"); //false: 不可枚举

 

枚举属性

除了检测对象的属性是否存在,我们还会经常遍历对象的属性。

var o = {x:1, y:2, z:3}; //三个可枚举的自有属性
o.propertyIsEnumerable("toString"); //false,不可枚举
for(p in o) //遍历属性
console.log(p); //输出x,y,z,不会输出toString;

除了for/in循环之外,还有两个用以枚举属性名称的函数。

第一个是Object.keys(),它返回一个数组,这个数组由对象中可枚举的自有属性和名称组成。

第二个是Object.getOwnPropertyNames().和Object.keys()类似。

 

 

属性getter和setter

对象属性是由名字,值 和一组特性构成的。属性值可以脾一个或两个方法替代,就是getter和setter。由他们定义的属性称为“存储器属性”(accessor property)。不同于数据属性(data property),数据属性只有一个简单的值。和数据属性不同,存取器属性不具有可写性。只有只读属性。

var 0 = {
	data_prop: value, //普通的数据属性
	get accessor_prop() { /*这里是函数体*/ },
	set accessor_prop() { /*这里是函数体*/ },
}

和数据属性一样,存取器属性是可以继承的。

var q = inherit(p); 
q.x = 1, q.y = 1; //给q添加两个属性
console.log(q.r); //可以使用继承的存取器属性
console.log(q.theta)

 

属性的特性

除了包含名字和值之外,属性还包含一些标识它们可写、可枚举和可配置的特性。

可以通过API给原型对象添加方法,并将它们设置为不可枚举,看起来像内置对象。

可以通过API给对象定义不能修改或删除的属性,借此“锁定”这个对象

数据属性的4个特性是:值 value,可写性writable,可枚举性enumerable,可配置性configwritable

存取器属性的4个特性是:可读get,写入set,可枚举性enumerable,可配置性configwritable

通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符:

Object.getOwnPropertyDescriptor({x:1},"x"); 
//返回{value: 1, writable: true, enumerable: true, configurable: true}

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

 

对象的三个属性

每一个对象都有与这相关的原型(prototype),类(class)和可扩展性(extensible attribute).

原型属性

要检测一个对象是否是另一个对象的原型,使用isPrototypeOf()方法。例如,可以通过p.isPrototypeOf(o)来检测p是否o的原型:

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

类属性

对象的类属性是一个字符串,用以表示 对象的类型信息。

要想获得对象的类,可以调用对象的toString()方法。

classof()函数可以传入任何类型的参数。数字、字符串和布尔值可以直接调用soString()方法一样。

function classof(o) {
	if( o=== null ) return "Null";
	if( o=== undefined ) return "Undefined";
	return Object.prototype.toString.call(o).slice(8,-1);
}

可扩展属性

对象的可扩展属性用以表示 是否可以给对象添加新属性。所有内置对象和自定义对象都是电显式可扩展的,宿主对象的可扩展性由Javascript引擎定义的。

通过将对象传入 Object.esExtensions(),来判断该对象是否是可扩展的。如果 想将对象设置为不可扩展,调用Object.preventExtension()。

Object.seal()可将对象设置为不可扩展,还可将对象的自有属性设置为不可配置。可以用Object.isSealed()来检测对象是否封闭。

Object.freeze()将更严格地锁定对象--“冻结”。Object.isFrozen()来检测对象是否冻结。

//创建一个封闭对象,包括一个冻结的原型和一个不可枚举的属性
var o = Object.seal(Object.create(Object.freeze({x:1} , y:{valus:2,writable:true})));

 

序列化对象

对象的序列化是指将对象的状态转换为字符串,也可将字符串还原为对象。

内置函数JSON.stringify()和JSON.parse()用来序列化和还原JS对象。

o = {x:1,y:[false,null,""]};
s = JSON.stringify(o);
p = JSON.parse(s); //p是o的深拷贝

对象方法

toString()方法

该方法没有参数,它将返回一个表示调用这个方法的对象值的字符串。

var s = {x:1, y:2}.toString();

console.log(s) //[object Object]

toLocaleString()方法

该方法返回一个表示这个对象的本地化字符串。

toJSON()方法

JSON.stringify()

valueOf()方法

将对象转换为某种原始值 而非字符串的时候才调用它。

 

更多详情查阅 《JavaScript权威指南》

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值