全面了解JavaScript对象进阶
前端之家收集整理的这篇文章主要介绍了
全面了解JavaScript对象进阶,
前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
@H_301_0@要了解JavaScript对象,我们可以从对象创建、属性操作、对象方法这几个方面入手。概括起来,包括以下几模块:
@H_
3010@1.创建对象
@H3010@1.1 对象直接量
@H301_0@对象直接量是创建对象最简单的方式,由若干名/值对组成映射表:
<div class="jb51code">
<pre class="brush:js;">
var point = {x: 0,y: 0 };
@H_
301_0@
属性名也没有什么限制,可以是js的关键字或者任意字符串,如果是这两种情况,
属性需要用双引号引起来:
@H_
301_0@对象直接量创建对象十分简单,但一般都不会这样使用。
代码可复用性低,如果想要在其他地方使用该对象并且
属性值不一样,那这么办?是不是又得重新创建一份
代码?
@H_
301_0@
1.2 通过new创建对象
@H_
301_0@通过new创建对象之前,先要创建一个
函数,new把这个
函数当做构造
函数(constructor)。例如通过new创建一个Person对象:
函数
}
var person = new Person();
@H_
301_0@Javscript语言核心中的原始类型都包含内置构造
函数:
@H_
301_0@
1.3 Object.create()
@H_
301_0@在了解Object的create
方法之前,我们想看看什么是原型。每一个Javascript对象(null除外)都和另一个对象相关联。“另一个”对象就是我们所说的原型。每一个对象都从原型继承
属性。
@H_
301_0@所有通过对象直接量创建的对象都具有同一个原型对象Object.prototype。关键字new和构造
函数创建的对象原型就是构造
函数的prototype
属性的值。通过new Array()创建对象的原型为Array.prototype,通过new Date()创建的对象原型为Date.prototype。原型暂介绍到这里。
@H_
301_0@Object.create
方法包含两个参数,第一个参数是对象的原型,第二个参数可选,用于描述对象
属性。使用很简单,只需传入所需的原型对象即可:
@H_
301_0@如果想创建一个没有原型的对象,可通过传入null作为参数。这样创建的对象不会继承任何
属性,也没有像toString这样的
方法:
@H_
301_0@如果想创建一个普通的空对象,直接传入Object.prototype:
@H_
301_0@如果是
自定义的对象,和创建空对象一样。直接传入对象名.prototype:
@H_
301_0@
@H_
301_0@
@H_
301_0@对象的
属性可通过点(.)或方括号([])运算符
获取。如果使用点
获取属性,
属性名必须是简单的表示符。不能是保留字,比如,o.for或者o.class。
错误
@H_
301_0@object[“property”]这种语法看起来更像数组,只是这个数组的元素是通过字符串索引而不是数字索引。这种数组就是我们所说的关联数组,也称为散列、映射或字典。Javascript对象都是关联数组。
@H_
301_0@既然对象是关联数组,那么Javascript也为我们提供了
属性的遍历方式for/in。下面的例子利用for/in计算portfolio的总计值:
return total;
}
@H_
301_0@继承:Javascript对象具有自有
属性(own property),也有一些
属性是从原型对象继承而来。我们先看看一个实现继承
功能的
函数inherit:
方法
}
var t = typeof p;
if(t !== "object" && t !== "function") throw TypeError();
function f() {};
f.prototype = p; //将其原型
属性设置为p
return new f();
}
@H_
301_0@假设要
查询对象o的
属性x,如果o中不存在x,将会继续在o的原型对象中
查询属性x。如果原型对象中也没有x,但这个原型对象也有原型,那么继续在这个原型对象的原型上执行
查询,直到找到x或者
查询到一个原型为null的对象为止。
3:x和y分别继承自o和p
@H_
301_0@
@H_
301_0@delete运算符可以
删除对象的
属性:
@H_
301_0@delete只能
删除自有
属性,不能
删除继承
属性。要
删除继承
属性,必须从定义这个
属性的原型对象上
删除它,而且这会影响到所有的继承自这个原型的对象。
删除成功会返回true。
删除x,返回true
delete o.x; //x已经不存在了,什么都没做,返回true。
delete o.toString; //什么都没做,返回true。
delete不能
删除可配置型为false的
属性。某些内置对象的
属性是不可配置的,比如通过变量声明和
函数声明创建的全局对象的
属性:
delete Object.prototype //不能
删除,
属性是不可配置的
var x = 1;
delete this.x; //不能
删除这个
属性
function f() {}
delete this.f; //不能
删除全局
函数
@H_
301_0@
2.3 检测属性
@H_
301_0@判断某个
属性是否存在于某个对象中,可通过in运算符、hasOwnProperty()和propetyIsEnumerable()
方法来检测。
@H_
301_0@in运算符:运算符左侧是
属性名,右侧是对象。如果对象的自有
属性或者继承
属性包含
属性则返回true:
属性
"y" in o; //false:y不是o的
属性
"toString" in o; //true:o继承toString
属性
@H_
301_0@hasOwnProperty()
方法:检测给定的名字是否是对象的自有
属性。对于继承
属性它将返回false:
属性x
o.hasOwnProperty("y"); //false:o中不存在
属性y
o.hasOenProperty("toString"); //false:toString是继承
属性
@H_
301_0@propertyIsEnumerable()
方法:是hasOwnProperty的增强版,只有检测到自有
属性并且这个
属性是可枚举行为true时才返回true:
属性x
o.propertyIsEnumerable("y"); //false:y是继承来的
Object.prototype.propertyIsEnumerable("toString"); //false:不可枚举
@H_
301_0@
2.4 枚举属性
@H_
301_0@通常使用for/in循环遍历对象
属性,遍历的
属性包括自有
属性和继承
属性。对象继承的内置
方法是不可枚举的,但在
代码中给对象
添加的
属性都是可枚举的。例如:
属性
o.propertyIsEnumeable("toString"); //false,不可枚举
for (p in o) //遍历
属性
console.log(p); //
输出x、y和z,不会
输出toString
@H_
301_0@有时候我们只想遍历自有
属性,并且
属性不为
函数:
@H_
301_0@我们可通过枚举遍历
功能实现可枚举
属性的复制:
属性复制到o中,并返回o
* 如果o和p含同名
属性,则覆盖o中的
属性
* 这个
函数并不处理getter和setter以及复制
属性
*/
function extend(o,p){
for(prop in p){ //遍历p中的所有
属性
o[prop] = p[prop]; //将
属性添加到o中
}
return o;
}
@H_
301_0@ES5定义了两个用以枚举
属性名称的
函数。第一个是Object.keys(),返回由对象中可枚举属自有
属性名称组成的数组。第二个枚举
函数是Object.getOwnPropertyNames(),和Object.keys()类似,它返回对象的所有自有
属性,而不仅仅是可枚举
属性。
@H_
301_0@
@H_
301_0@
3.1 属性getter和setter
@H_
301_0@对象
属性由名字、值和一组特性(attribute)构成的。在ES5中,
属性值可以用一个或两个
方法替代,这两个
方法就是getter和setter。由getter和setter定义的
属性称做“存取器
属性”,它不同于“数据
属性”,数据
属性只有一个简单的值。
@H_
301_0@和数据
属性不同,存取器
属性不具有可写性(writeable atribute)。如果
属性同时具有getter和setter
方法,那么它是一个读/写
属性。如果它只有getter
方法,那么它是一个只读
属性,如果它只有setter
方法,那么它是一个只写
属性。读取只写
属性总是返回undefined。
@H_
301_0@存取器
属性定义语法也比较简单,
函数定义没有使用function关键字,而是使用get或set:
属性
data_prop: 1,//存取器
属性都是成对定义的
函数
get accessor_prop(){/* 这里是
函数体 */},set accessor_prop(value){}
};
@H_
301_0@思考下面这个表示2D笛卡尔点坐标的对象。它有两个普通
属性x和y分别表示x坐标和y坐标,它还有两个等价的存取器
属性用来表示点的极坐标:
属性
x: 1.0,y: 1.0,//r是可读写的存取器
属性,它有getter和setter
get r(){return Math.sqrt(this.x * this.x + this.y * this.y); },set r(newValue){
var oldValue = Math.sqrt(this.x * this.x + this.y * this);
var ratio = newValue / oldValue;
this.x *= ratio;
this.y *= ratio;
},//theta是只读存取器
属性,只有getter
方法
get theta() { return Math.
atan2(this.y,this.x); }
};
@H_
301_0@和数据
属性一样,存取器
属性是可以继承的,因此可以将上述
代码中的p对象当做另一个“点”的原型。可以给性对象定义它的x和y
属性,但r和theta
属性继承而来:
@H_
301_0@
3.2 属性特性
@H_
301_0@我们可以将存取器
属性的getter和setter
方法看成
属性的特性。按照这个逻辑,我们也可把
属性的值同样看着
属性的特性。因此,可以认为一个
属性包含一个名字和4个特性。
@H_
301_0@数字
属性的4个特性分别是它的值(value)、可写性(writeable)、可枚举性(enumerable)和可配置型(configurable)。
@H_
301_0@存取器
属性不具有值(value)特性和可写性,因此包含:读取(get)、写入(set)、可枚举性、可配置性。
@H_
301_0@ES5定义了一个名为“
属性描述符”的对象,这个对象代表那4个特性。数据
属性的描述符对象的
属性有value、writable、enumerable和configurable。存取器
属性的描述符对象则用get
属性和set
属性代替value和writable。其中writable、enumerable、configurable都是布尔值,get
属性和set
属性是
函数值。
@H_
301_0@通过
调用Object.getOwnPropertyDescriptor()可以
获取某个对象特定
属性的
属性描述符:
查询上文中定义的random对象的octet
属性
//返回{get: /*func */,set: undefined,configurable: true}
Object.getOwnPropertyDesciptor(random,"octet");
//对于继承属性和不存在属性,返回undefined
Object.getOwnPropertyDesciptor({},"x");
Object.getOwnPropertyDesciptor({},"toString");
@H_
301_0@从
函数名就可以看出,Object.getOwnPropertyDesciptor()只能得到自有
属性的描述符。要想获得继承
属性的特性,需要遍历原型链(Object.getPrototypeOf())。
@H_
301_0@想要设置
属性的特性,或者让新建
属性具有某些特性,则需要
调用Object.defineProperty(),包含三个参数:对象、
属性名、
属性描述符对象:
1
Object.keys(o) //=> []
//现在对
属性x做
修改,让它变成只读
Object.defineProperty(o,"x",{writable: true });
//视图更改这个
属性的值
o.x = 2; //操作失败但不报错,而在严格模式中抛出类型
错误异常
//
属性依然是可配置的,因此可通过这种方式对它进行
修改:
Object.defineProperty(o,{value: 2 });
o.x //=> 2
//现在将x从数据
属性修改为存取器
属性
Object.defineProperty(o,{ get: function() {return 0;} });
o.x // => 0
@H_
301_0@如果要同时
修改或创建多个
属性,则需要使用Object.defineProperties()。第一个参数是要
修改的对象,第二个参数㐊一个映射表。例如:
@H_
301_0@
getter和setter的老式API:
在ES5采纳之前,大多数Javascript的实现已经可以
支持对象直接量语法中get和set写法。这些实现提供了非标准的老式API用来
查询和设置getter和setter。这些API由四个
方法组成,所有对象都拥有这些
方法。
@H_
301_0@__lookupGetter__()和__lookupSetter__()用以返回一个命名
属性的getter和setter
方法。
@H_
301_0@__defineGetter__()和__defineSetter__()用以定义getter和setter,第一个参数是
属性名字,第二个参数是getter和setter
方法。
@H_
301_0@
4.对象的三个属性
@H_
301_0@每一个对象都有与之相关的原型(prototype)、类(class)、可扩展性(extensible attribute)。接下来讲述这些
属性有什么作用。
@H_
301_0@
4.1 原型属性
@H_
301_0@对象的原型
属性是用来继承
属性的,我们经常把“o的原型
属性”直接叫做“o的原型”。在之前“创建对象”介绍了三种方式创建对象。通过对象直接量创建的对象使用Object.prototype作为它们的原型。通过new创建的对象使用构造
函数的prototype
属性作为它们的原型。通过Object.create()创建的对象使用第一个参数作为它们的原型。
@H_
301_0@在ES5中,可通过Object.getPrototypeOf()
查询对象原型。在ES3中,没有与之等价的
函数,而是使用表达式o.constructor.prototype检查对象的原型。
@H_
301_0@要想检测一个对象是否是另一个对象的原型(或处于原型链中),使用isPrototypeOf()
方法。例如,可以通过p.isPrototypeOf(o)来检测p是否是o的原型:
true,o继承自p
Object.prototype.isPrototypeOf(o) //=> true,p继承自Object.prototype
@H_
301_0@Mozilla实现的Javascript
对外暴露了一个专门命名为__proto__
属性,用以直接
查询/设置对象原型。但IE和Opera
不支持__proto__
属性,所以不建议直接使用__proto__
属性。
@H_
301_0@
4.2 类属性
@H_
301_0@对象的类
属性是一个字符串,用以表示对象的类型信息。ES3和ES5都为提供设置这个
属性的
方法,只有一种间接方式
查询它。默认的toString()
方法返回这种格式的字符串:[object class]。
@H_
301_0@可通过
调用toString()
方法,然后
提取已返回字符串的第八个到倒数第二个位置之间的字符。但有个麻烦是,很多对象继承的toString()
方法重写了,为了能够
调用正确的toString()版本,必须间接
调用Function.call()
方法。下面例子的classof
函数可返回任意对象的类:
@H_
301_0@
4.3 可扩展性
@H_
301_0@对象的可扩展性用以表示是否可以给对象
添加新
属性。所有内置对象和
自定义对象都是显式可扩展的。在ES5中,可将对象转换为不可扩展的。
@H_
301_0@Object.seal()
方法除了能够将对象设置为不可扩展的,还可以将对象的所有自有
属性都设置为不可配置的。也就是说,不能给对象
添加新
属性,而且已有
属性也不能
删除和配置。
@H_
301_0@Object.isSealed()
方法用来检测对象是否封闭。
@H_
301_0@Object.freeze()
方法将更严格的锁定对象,除了拥有Object.seal()
方法的
功能外,还可以将自有的所有数据
属性设置为只读(如果对象的存取器
属性有setter
方法,存取器
属性不受影响, 仍可以通过给
属性赋值
调用它们)。
@H_
301_0@Object.isFrozen()用来检测对象是否冻结。
@H_
301_0@
5.序列化对象
@H_
301_0@对象序列化是指将对象的状态转换为字符串,也可以将字符串还原为对象。ES5提供了内置
函数JSON.stringify()和JSON.parse()用来序列化和还原Javascript对象。这些
方法都使用JSON作为数据交换格式。例如:
@H_
301_0@JSON的语法是Javscript语法的子集,它并不能表示Javascript里的所有值。
支持对象、数组、字符串、无穷大数字、true、false和null,并且它们可以序列化和还原。NaN、Inifinity和-Inifinity序列化结果都是null。
函数、RegExp、Error对象和undefined值不能序列化和还原。
@H_
301_0@
这里在附加说一下对象的方法:
@H_
301_0@
toString()方法:它将返回一个表示调用这个方法的对象值的字符串。很多对象都重写了toString()方法,比如Array.toString()、Date.toString()以及Function.toStrring()。
@H_301_0@toJSON()方法:Object.prototype实际上没有定义toJSON()方法,但由于需要执行序列化的对象来说,JSON.stringify()方法会调用toJSON()方法。如果在带序列化的对象中存在这个方法,则调用它。
@H_301_0@valueOf()方法:valueOf()方法和toString()方法非常相似,但往往Javascript需要将对象转换为某种原始值而非字符串的时候才调用它,尤其是转换为数字的时候。有些内置类自定义了valueOf()方法,比如,Date.valueOf()。
@H_301_0@以上这篇全面了解JavaScript对象进阶就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持编程之家。 原文链接:https://www.f2er.com/js/47206.html