《JavaScript权威笔记(第六版)》笔记0x4 对象

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/funkstill/article/details/88414081

    对象是JavaScript的基本数据类型。对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。对象也可看做是属性的无序集合,每个属性都是一个名/值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。JavaScript对象还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性。这种“原型式继承”(prototypal inheritance)是JavaScript的核心特征。

    JavaScript对象是动态的——可以新增属性也可以删除属性——但它们常用来模拟静态对象以及静态类型语言中的“结构
体”(struct)。有时它们也用做字符串的集合(忽略名/值对中的值)。
    除了字符串、数字、 true、 false、 null和undefined之外, JavaScript中的值都是对象。尽管字符串、数字和布尔值不是对象,但它们的行为和不可变对象非常类似。

    对象最常见的用法是创建(create)、设置(set)、查找(query)、删除(delete)、检测(test)和枚举(enumerate)它的属性。

    属性特性

  • 可写(writable attribute),表明是否可以设置该属性的值。
  • 可枚举(enumerable attribute),表明是否可以通过for/in循环返回该属性。
  • 可配置(configurable attribute),表明是否可以删除或修改该属性。
  • 对象的原型(prototype)指向另外一个对象,本对象的属性继承自它的原型对象。
  • 对象的类(class)是一个标识对象类型的字符串。
  • 对象的扩展标记(extensible flag)指明了(在ECMAScript 5中)是否可以向该对象添加新属性。

    三类JavaScript对象和两类属性

  • 内置对象(native object)是由ECMAScript规范定义的对象或类。例如,数组、函数、日期和正则表达式都是内置对象。
  • 宿主对象(host object)是由JavaScript解释器所嵌入的宿主环境(比如Web浏览器)定义的。客户端JavaScript中表示网页结构的HTMLElement对象均是宿主对象。既然宿主环境定义的方法可以当成普通的JavaScript函数对象,那么宿主对象也可以当成内置对象。
  • 自定义对象(user-defined object)是由运行中的JavaScript代码创建的对象。
  • 自有属性(own property)是直接在对象中定义的属性。
  • 继承属性(inherited property)是在对象的原型对象中定义的属性。

创建对象

     对象直接量

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

    通过new创建对象

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

    Object.create()

var o1=Object.create({x:1,y:2});//o1继承了属性x和y
var o2=Object.create(null);//o2不继承任何属性和方法
var o3=Object.create(Object.prototype);//o3和{}和new Object()一样

/*通过原型继承创建一个新对象*/
//inherit()返回了一个继承自原型对象p的属性的新对象
//这里使用ECMAScript 5中的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"&&t!=="function")throw TypeError();
    function f(){};//定义一个空构造函数
    f.prototype=p;//将其原型属性设置为p
    return new f();//使用f()创建p的继承对象
}

属性的查询和设置

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

object.property
object["property"]

    作为关联数组的对象

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

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

     继承

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

var o={}//o从Object.prototype继承对象的方法
o.x=1;//给o定义一个属性x
var p=inherit(o);//p继承o和Object.prototype
p.y=2;//给p定义一个属性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

    属性赋值操作首先检查原型链,以此判定是否允许赋值操作。例如,如果o继承自一个只读属性x,那么赋值操作是不允许的。如果允许属性赋值操作,它也总是在原始对象上创建属性或对已有的属性赋值,而不会去修改原型链。在JavaScript中,只有在查询属性时才会体会到继承的存在,而设置属性则和继承无关,这是JavaScript的一个重要特性,该特性让程序员可以有选择地覆盖(override)继承的属性。

删除属性

    delete运算符可以删除对象的属性。它的操作数应当是一个属性访问表达式。让人感到意外的是, delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。

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

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

检测属性

/*in运算符*/
var o={x:1}
"x"in o;//true
"y"in o;//false
"toString"in o;//true

/*hasOwnProperty()*/
var o={x:1}
o.hasOwnProperty("x");//true
o.hasOwnProperty("y");//false
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

属性getter和setter

    对象属性是由名字、值和一组特性(attribute)构成的。在ECMAScript 5 [8]中,属性值可以用一个或两个方法替代,这两个方法就是getter和setter。由getter和setter定义的属性称做“存取器属性”(accessor property),它不同于“数据属
性”(data property),数据属性只有一个简单的值。

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

/*笛卡尔坐标对象*/
var p={
    //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.y);
        var ratio=newvalue/oldvalue;
        this.x*=ratio;
        this.y*=ratio;
    },//theta是只读存取器属性,它只有getter方法
    get theta(){return Math.atan2(this.y,this.x)};)
};

对象的三个属性

    原型属性

    对象的原型属性是用来继承属性的。原型属性是在实例对象创建之初就设置好的。

    要想检测一个对象是否是另一个对象的原型(或处于原型链中),请使用isPrototypeOf()方法。

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

     类属性

    对象的类属性(class attribute)是一个字符串,用以表示对象的类型信息。要想获得对象的类,可以调用对象的toString()方法,然后提取已返回字符串的第8个到倒数第二个位置之间的字符。不过让人感觉棘手的是,很多对象继承的toString()方法重写了,为了能调用正确的toString()版本,必须间接地调用Function.call()方法。

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

    classof()函数可以传入任何类型的参数。数字、字符串和布尔值可以直接调用toString()方法,就和对象调用toString()方法一样 ,并且这个函数包含了对null和undefined的特殊处理(在ECMAScript 5中不需要对这些特殊情况做处理)。通过内置构造函数(比如Array和Date)创建的对象包含“类属性”(class attribute),它与构造函数名称相匹配。宿主对象也包含有意义的“类属性”,但这和具体的JavaScript实现有关。通过对象直接量和Object.create创建的对象的类属性是"Object",那些自定义构造函数创建的对象也是一样,类属性也是"Object",因此对于自定义的类来说,没办法通过类属性来区分对象的类:

classof(null)//=>"Null"
classof(1)//=>"Number"
classof("")//=>"String"
classof(false)//=>"Boolean"
classof({})//=>"Object"
classof([])//=>"Array"
classof(/./)//=>"Regexp"
classof(new Date())//=>"Date"
classof(window)//=>"Window"(这是客户端宿主对象)
function f(){};//定义一个自定义构造函数
classof(new f());//=>"Object"

     可扩展性

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

序列化对象

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

o={x:1,y:{z:[false,null,""]}};//定义一个测试对象
s=JSON.stringify(o);//s是'{"x":1,"y":{"z":[false,null,""]}}'
p=JSON.parse(s);//p是o的深拷贝

猜你喜欢

转载自blog.csdn.net/funkstill/article/details/88414081