Cocos Creator_JavaScript权威指南(第六版)_第6章_对象

本文详细介绍了JavaScript中的对象,包括对象的性质、创建方法、原型、属性的查询和设置、继承、删除以及属性特性。对象是属性的无序集合,可以有自有属性和继承属性,通过对象直接量、new运算符或Object.create()创建。对象的原型链决定了属性继承,而属性的可写性、可枚举性和可配置性可以通过Object.getOwnPropertyDescriptor()和Object.defineProperty()进行控制。此外,文章还探讨了对象的toString()、toLocaleString()、valueOf()等方法以及JSON序列化。
摘要由CSDN通过智能技术生成

对象是JavaScript的基本数据类型。对象是一种复合值:它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。对象也可看做是属性的无序集合,每个属性都是一个名/值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。这种基本数据结构还有很多种叫法,有些我们依然非常熟悉,比如“散列(hash)”、“散列表(hashtable)”、“字典(dictionary)”、“关联数组(associativearray)”。然而对象不仅仅是字符串到值的映射,除了可以保持自有的属性,JavaScript对象还可以从一个称为原型的对象继承属性。对象的方法通常是继承的属性。这种“原型式继承”(prototypal inheritance)是JavaScript的核心特征。
JavaScript对象是动态的——可以新增属性也可以删除属性——但他们常用模拟对象以及静态类型语言中的“结构体”(struct)。有时他们也用做字符串的集合(忽略名/值对中的值)。
除了字符串、数字、true、false、null和undefined之外,JavaScript中的值都是对象。尽管字符串、数字和布尔值不是对象,但他们的行为和不可变对象(3.6)非常类似。
3.7中了解到,对象是可变的,我们通过引用而非值来操作对象。如果变量x是指向一个对象的引用,那么执行代码var y = x;变量y也是指向同一个对象的引用,而非这个对象的副本。通过变量y修改这个对象亦会对变量x造成影响。
对象最常见的用法是创建(create)、设置(set)、查找(query)、删除(delete)、检测(test)和枚举(enumerate)它的属性。
属性包括名字和值。属性名可以是包含空字符串在内的任意字符串,但对象中不能存在两个同名的属性。值可以是任意JavaScript值,或者(ECMAScript5中)可以是一个getter或setter函数(或两者都有)。6.6会有关于getter和setter函数的讲解。除了名字和值之外,每个属性还有一些与之相关的值,称为“属特性”:
·可写,表明是否可以设置该属性的值。
·可枚举,表明是否可以通过for/in循环返回该属性。
·可配置,表明是否可以删除或修改该属性。
在ECMAScript 5之前,通过代码给对象创建的所有属性都是可写的、可枚举的和可配置的。在ECMAScript 5中则可以对这些特性加以配置。6.7讲述如何操作。
除了包含属性之外,每个对象还拥有三个相关的对象特性:
·对象的原型指向另外一个对象,本对象的属性继承自它的原型对象。
·对象的类是一个标识对象类型的字符串
·对象的扩展标记指明了(在ECMAScript 5中)是否可以向该对象添加新属性。
6.1.3和6.2.2会有关于原型和属性继承的讲述,6.8会进一步详细讲述这三个特性。

最后,用以下术语来对三类JavaScript对象和两类属性作区分:
·内置对象是有ECMAScript规范定义的对象或类。例如,数组、函数、日期和正则表达式都是内置对象。
·宿主对象是由JavaScript解释器所嵌入的宿主环境(比如Web浏览器)定义的。客户端JavaScript中表示网页结构的HTMLElement对象均是宿主对象。既然宿主环境定义的方法可以当成普通的JavaScript函数对象,那么宿主对象也可以当成内置对象。
·自定义对象是由运行中的JavaScript代码创建的对象。
·自有属性是直接在对象中定义的属性。
·继承属性是在对象的原型对象中定义的属性。

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

6.1.1 对象直接量
创建对象最简单的方式就是在JavaScript代码中使用对象直接量。对象直接量是由若干名/值对组成的映射表,名/值对中间用冒号分隔,名/值对之间用逗号分隔,整个映射表用花括号括起来。属性名可以是JavaScript标识符也可以是字符串直接量(包括空字符串)。属性的值可以是任意类型的JavaScript表达式,表达式的值(可以是原始值也可以是对象值)就是这个属性的值。下面有一些例子:

        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"
            }
        }

在ECMAScript 5(以及ECMAScript 3的一些实现)中,保留字可以用做不带引号的属性名。然后对于ECMAScript 3来说,使用保留字作为属性名必须使用引号引起来。在ECMAScript 5中,对象直接量中的最后一个属性后的逗号将忽略,且在ECMAScript 3的大部分实现中也可以忽略这个逗号,但在IE中则报错。
对象直接量是一个表达式,这个表达式的每次运算都创建并初始化一个新的对象。每次计算对象直接量的时候,也都会计算他的每个属性的值。也就是说。如果在一个重复调用的函数中的循环体内使用了对象直接量,它将创建很多新对象,并且每次创建的对象的属性值也有可能不同。

6.1.2通过new创建对象
new运算符创建并初始化一个新对象。关键字new后跟随一个函数调用。这里的函数称做构造函数(constructor),构造函数用于初始化一个新创建的对象。JavaScript语言核心中的原始类型都包含内置构造函数。例如:

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

除了这些内置构造函数,用自定义构造函数来初始化新对象也是非常常见的。(9)

6.1.3 原型
在了解第三种对象创建技术之前,我们应当首先了解一下原型。每一个JavaScript对象null除外)都和另一个对象相关联。“另一个”对象就是我们熟知的原型,每一个对象都从原型继承属性。
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JavaScript代码Object.prototypr获得对原型对象的引用。通过关键字new和构造函数调用创建的对象的原型就是构造函数的prototype属性的值。因此,同使用{}创建对象一样,通过new Object()创建的对象也继承自Object.prototype。同样,通过new Array()创建的对象的原型就是Array.prototype,通过new Date()创建的对象的原型就是Date.prototype。
没有原型的对象为数不多,Object.prototyp就是其中之一。他不继承任何属性。其他原型对象都是普通对象,普通对象都具有原型。所有的内置构造函数(以及大部分自定义的构造函数)都具有一个继承自Object.prototypr的原型。例如,Date.prototype的属性继承自Object.prototype,因此有new Date()创建的Date对象的属性同时继承自Date.prototype和Object.prototrpe。这一系列链接的原型对象就是所谓的“原型链”(prototype chain)。
6.2.2讲述属性继承的工作机制。6.8.1将会讲到如何获取对象的原型。第九章会更详细地讨论原型和构造函数,包括如何通过编写构造函数定义对象的“类”,以及给构造函数的prototype属性赋值可以让其“实例”直接使用这个原型上的属性好方法。

6.1.4 Object.create()
ECMAScript 5定义了一个名为Object.create()的方法,它创建一个新对象,其中第一个参数是这个对象的原型。Object.create()提供第二个可选参数,用以对对象的属性进行进一步描述。6.7会详细讲述第二个参数。
Object.create()是一个静态函数,而不是提供给某个对象调用的方法。使用它的方法很简单,只须传入所需的原型对象即可:

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

可以通过传入参数null来创建一个没有原型的新对象,但通过这种方式创建的对象不会继承任何东西,甚至不包括基础方法,比如toString(),也就是说,它将不能和“+”运算符一起正常工作:

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

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

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

可以通过任意原型创建新对象(换句话说,可以使任意对象可继承),这是一个强大的特性。在ECMAScript 3中可以用类似下面的代码来模拟原型继承:


//inherit()返回了一个继承自原型对象p的属性和新对象
//这里使用ECMAScript 5中的Object.create()函数(如果存在的话)
//如果不存在Object.create(),则退化使用其他方法
      inherit:function (p) {
   
      if (p==null)                     //p是一个对象,但不能是null
      throw TypeError();
      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的继承对象
    },

PS:inherit()并不能完全代替Object.create(),他不能通过传入null原型来创建对象,而且不能接收可选的第二个参数。
inherit()函数的其中一个用途就是防止库函数无意间(非恶意地)修改那些不受你控制的对象。不是将对象直接作为参数传入函数,而是将它的继承对象传入函数。当函数读取继承对象的属性时,实际上读取的是继承来的值。如果给继承对象的属性赋值,则这些属性只会影响这个继承对象自身,而不是原始对象:

var o = {x:"don`t change this value"};
library_function(inherit(0));//防止对o的意外修改

6.2 属性的查询和设置
4.4中提到,可以通过电(.)或方括号([])运算符来获取属性的值。运算符左侧应当是一个表达式,他返回一个对象。对于点(.)来说,右侧必须是一个以属性名称命中的简单标识符。对于方括号来说([]),方括号内必须是一个计算结果为字符串的表、表达式,这个字符串就是复兴的名字:

       var book = {              
            "main title":"JavaScript",      
            'sub-title':"The Definitive Guide",
            "for":"all audiences",            
            author:{                        
                firstname:"David",            
                surname:"Flanagan"
            }
        }

        var author = book.author; //得到book的“author”的属性 undefined
        var name = author.surname; //得到获得author的"surname"属性Canvas<HelloWorld>
        var title = book["main title"];//得到book的“main title”属性  undefined

和查询属性值的写法一样,通过点和方括号也可以创建属性或给属性赋值,但需要将他们放在赋值表达式的左侧:

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

在ECMAScript 3中,点运算符后的标识符不能是保留字,比如,o.for或o.class是非法的,因为for是JavaScript的关键字,class是保留字。如果一个对象的属性名是保留字,则必须使用方括号的形式访问它们,比如o[“for”]和o[“class”]。ECMAScript 5对此放宽了限制(包括ECMAScript 3的某些实现),可以在点运算符后直接使用保留字。
当使用方括号时,我们说方括号内的表达式必须返回字符串。其实更严格的将,表达式必须返回字符串或返回一个可以转换为字符串的值。

6.2.1 作为关联数组的对象
上文提到,下面两个JavaScript表达式的值相同:
object.property
object[“property”]
第一种语法使用点运算符和一个标识符,这和C和Java中访问一个结构体或对象的静态字段非常类似。第二种语法使用方括号和一个字符串,看起来更像数组,只是这个数组元素是通过字符串索引而不是数字索引。这种数组就是我们所说的关联数组,也称做散列、映射或字典。JavaScript对象都

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值