第六章 对象
6.1 创建对象
6.1.1 对象直接量
- Q:什么是对象直接量: 是一个用花括号括起来的映射表。表中元素为名/值对,名/值对间用逗号隔开,名和值之间用冒号隔开。
- Q:对象直接量有啥特点: 对象直接量是一个表达式,该表达式的每次运算丢会创建并初始化一个新的对象
6.1.2 通过new创建对象
Q:new怎么创建对象? new运算符后跟一个构造函数,构造函数用以初始化一个新创建的对象
var a = new Object();//创建一个空对象,和{}一样
var b = new Array(); //创建一个空数组,和[]一样
var c = new Date(); //创建一个表示当前时间的date对象
var d = new RegExp('js'); //创建一个可以进行模式匹配的EegExp对象
Q:在new调用构造函数时,发生了什么? : (1) 创建一个新对象; (2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ; (3) 执行构造函数中的代码(为这个新对象添加属性) ;
6.1.3 原型
Q:原型是什么? : 每一个JavaScript对象(null)除外都和另一个对象相关联。这里的另一个对象指的就是原型,每一个对象都从原型继承属性。
Q: 原型主要的作用是什么? : 用于继承
Q:通过对象直接量创建的对象和通过new字符串+构造函数创建的对象的原型有什么区别?
: (1)对象直接量创建的对象:都具有同一个原型对象,可以通过 object.prototype获得原型对象的引用
(2)new+构造函数创建的对象:原型是构造函数的prototype属性的值,每个构造函数都有prototype属性。因此,使用对象直接量创建的对象与new Object()创建的对象的原型是一样的。
Q:还有什么需要注意的点?
: (1) 并不是所有对象都有原型,object.prototype没有原型,它不继承任何属性。
(2) 所有内置构造函数以及大部分自定义构造函数都具有一个继承自object.prototype的原型。
6.1.4 Object.create()
Q: Object.create()的用法?
: 创建一个新对象,方法接收两个参数。第一个参数为该对象的原型,6.7节讲第二个参数。例子如下:
var a = Object.create({x:1,y:2}) //a继承了属性x和y
Q: Object.create() 创建空对象
: (1) 创建一个没有原型的空对象:
var b = Object.create(null); //b不继承任何属性和方法,甚至不包括toString()这样的基础方法,也就是说,不能和'+'运算符一起正常工作
(2) 创建一个普通空对象:
var c = Objet.create(Object.prototype); //c和{}和new Object() 一样
6.2 属性的查询和设置
Q: 属性怎么查询?
: (1) 通过(.)运算符来查询:该方式的左侧为一个表达式,返回一个对象,右侧必须是一个以属性名称命名的简单标识符。
(2) 通过([ ])运算符来查询:该方式的方括号内必须是一个计算结果为字符串的表达式或者返回一个可以转换为字符串的值,这个字符串就是属性的名字。
两种方式的例子如下:
var author = book.author;
var title = book["main title"];
Q: 属性怎么设置?
: (1) 通过(.)运算符来设置
(2) 通过([ ])运算符来设置
两种方式的例子如下:
book.edition = 6;
book["main rirle"] = "pig";
6.2.1 作为关联数组的对象
Q: 什么是关联数组?
: 使用字符串进行索引的数组就是关联数组。js中的对象都是关联数组,因为对象的值可以通过对象名["字符串"]来得到。
Q: 通过[ ]访问对象的属性和通过 . 访问对象的属性有什么不同? : [ ]使用字符串访问属性值。是动态的,可以在运行时更改,可以是变量;. 后面只能是固定的标识符,标识符是静态的,是已知的,必须写死在程序中。
6.2.2 继承
Q: 继承是通过什么来实现的? : 通过原型链来实现属性的继承
Q:原型链是怎么形成的? : 原型链是靠__proto__来维持的,一个继承父函数的子函数的对象都有一个内部属性__proto__,该属性包含一个指针,指向父函数的prototype,父函数也继承了某个函数,其__proto__又指向它的父函数的prototype,这样一直网上找,知道找到Object.prototype,再上层的__proto__为null,这样就形成了原型链
Q:属性赋值会改变原型对象的值吗? : 不会
6.2.3 属性访问错误
Q: 查询一个不存在的属性会报错吗?
: 不会。如果在对象自身的属性和原型链上的属性中均未找到属性x,返回undefined。 book.subtitle; //undefined 属性不存在
Q: 在什么情况下,查询属性会报错?
: 当对象不存在时,查询这个不存在的对象的属性就会报错。例如,null和 undefined值都没有属性,查询就会报错。例如,接上例:var len = book.subtitle.length; //跑出类型错误异常,因为前者为undefined,undefined没有length属性
Q:还有什么要注意的?
: 有些对象不允许新增属性,但是设置属性的失败操作不会报错。例如:Object.prototype = 0;//内置构造函数的原型是只读的,不能修改。这里赋值失败,但没报错,也没有赋值成功。
这是一个历史遗留问题,在ECMAScript 5的严格模式中已经修复。
6.3 删除属性
- delete 运算符可以删除对象的属性。
- delete 只能删除自有属性,不能删除继承属性。
- delete 不能删除可配置性为false的属性
6.4 检测属性
Q:怎样判断某个属性是否存在于某个对象中? : 可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法来完成这个工作,甚至仅通过属性查询也可以做到这一点。 (1)in运算符:左侧是属性名,右侧是对象。如果对象的自由属性或继承属性中包含这个属性则返回true。 (2)hasOwnPreperty():对象的自有属性返回true,继承属性返回false (3)propertyIsEnumerable():自有属性切可枚举返回true,继承属性返回false
6.5 枚举属性
Q:可枚举属性的函数有哪些? : (1)for/in (2)Object.keys(): 返回一个数组,数组由可枚举的自有属性的名称组成 (3)Object.getOwnPropertyNames():返回对象的所有自有属性的名称
6.6 属性getter和setter
Q: 属性getter和setter有啥用?
: 可以定义对象的属性,由getter和setter定义的属性称为存取器属性,普通定义的属性称为“数据属性”,“数据属性“只有一个简单的值。
Q: 存取器属性的特点 : 与数据属性一样,可以继承;由getter和setter方法构成。可以只有getter方法或者只有setter方法或者两者都有。三种构成有啥区别嘞? (1)只有getter方法:存取器属性是一个只读属性,不能修改。 (2)只有setter方法:只一个只写属性,不可读取。 (3)两种方法都有:是个可读可写属性。
Q: 怎样用getter和setter定义属性?
: >var obj = {
x: 1,
y: 2,
get a() {
return this.x + this.y
},
set a(newVal) {
var oldVal = this.x+this.y;
var a = newVal / oldVal;
this.x += a;
this.y += a;
}
}
console.log(obj.a); //3 读取a的时候会调用get方法,返回x+y的值
obj.a = 6; //设置a的时候会调用set方法,newVal为6,a算出等于2,x等于3,y等于4,得出a等于6
console.log(obj.a);//6
: 这里的a属性就是使用getter和setter定义的存取器属性,set和get方法里的this指向属性所属的对象。
6.7 属性的特性
Q:属性的特性有啥,存取器属性呢 ?
: 一个属性包含一个属性名称和四个特性。四个特性分别是:
(1)属性值
(2)可写性
(3)可枚举性
(4)可配置性
存取器属性不具有值特性和写特性。因此存取器属性的四个特性为:读取、写入、可枚举性和可配置性
Q: 数据属性和存取器属性的属性描述符对象是什么? : >属性描述符对象的数学那个和它们嗦描述的属性特性是同名的
: 因此,
数据属性的属性描述符对象为:value、writable、enumerable、configurable
存取器属性的属性描述符对象:ger、set、enumerable、configurable
Q:怎样获得对象某个特定属性的的属性描述符对象?
: 通过Object.getOwnPropertyDescriptor()可获得,接收两个参数,第一个参数为对象,第二个参数为对象的属性,改方法只能得到自有属性的属性描述符,怎样得到继承属性的属性描述符呢?需要遍历原型链。
Q: 怎样设置属性的特性?
: 通过调用Object.definePeoperty(),传入要修改的对象、要创建或修改的属性的名称以及属性描述符对象。对于新创建的属性来说,默认的特性值是false或者undefined。对于修改的已有属性来说,默认的特性值没有做任何修改。如果要同时修改或创建多个属性,使用Object.defineProperies()
6.8 对象的三个属性
三个属性分别为原型属性、类属性、可扩展性属性
6.8.1 原型属性
Q: 原型属性是用来干嘛的? : 哦你过来继承属性的。原型属性在实例对象创建之初就设置好了。
Q:怎样检测一个对象是否是另一个对象的原型?
: 使用isPrototypeOf()方法
6.8.2 类属性
对象的类属性是一个字符串,用以表示对象的类型信息。
Q: 怎样获得对象的类?
: 调用对象的toString()方法
6.8.3 可扩展性
队形的可扩展性用以表示是否可以给对象添加新属性。所有内置对象和自定义对象都是可扩展的,,除非将它们转成不可扩展的。
6.9 序列化对象
Q:什么是对象序列化? : 指的是将对象的状态转换为字符串,也可将字符串还原为对象。
Q:通过什么方法转换对象和字符串?
: JSON.stringify()和JSON.parse用来序列化和还原
6.10 对象方法 之后再补充
6.10.1 toString()方法
该方法没有参数,返回一个表示调用这个方法的对象之的字符串