JavaScript权威指南学习笔记

JavaScript权威指南学习笔记

  • 第六章 对象
    • 6.1 创建对象
      • 6.1.1 对象直接量
      • 6.1.2 通过new创建对象
      • 6.1.3 原型
      • 6.1.4 Object.create()
    • 6.2 属性的查询和设置
      • 6.2.1 作为关联数组的对象
      • 6.2.2 继承
      • 6.2.3 属性访问错误
    • 6.3 删除属性
    • 6.4 检测属性
    • 6.5 枚举属性
    • 6.6 属性getter和setter
    • 6.7 属性的特性
    • 6.8 对象的三个属性
      • 6.8.1 原型属性
      • 6.8.2 类属性
      • 6.8.3 可扩展性
    • 6.9 序列化对象
    • 6.10 对象方法 之后再补充
      • 6.10.1 toString()方法
      • 6.10.2 toLocaleString()方法
      • 6.10.3 toJSON()方法
      • 6.10.4 valueOf() 方法

第六章 对象

6.1 创建对象

6.1.1 对象直接量

  1. Q:什么是对象直接量: 是一个用花括号括起来的映射表。表中元素为名/值对,名/值对间用逗号隔开,名和值之间用冒号隔开。
  2. 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: 在什么情况下,查询属性会报错?
当对象不存在时,查询这个不存在的对象的属性就会报错。例如, nullundefined值都没有属性,查询就会报错。例如,接上例: 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()方法

该方法没有参数,返回一个表示调用这个方法的对象值的字符串,在对象需要进行类型转换时,会调用这个方法。默认的toString()返回的信息很少,对象默认的toString会生成[object classname]的结果,第一个object表示变量是对象,不是值类型,classname表示该对象的类名。[object Object]前面一个object表示他是对象,后面一个Object表示它是Object类的,例如:
var obj = {name:'ww'}; obj.toString();//[object Object];

6.10.2 toLocaleString()方法

所有对象都有toLocaleString()方法。但是大部分对象的该方法都与toString()用法相同,因为在调用toLocaleString()是会自动调用toString()方法。有两个对象除外,Date和Number类,它们对toLocaleString()方法做了定制,可以用它对数字、日期和时间做本地化对转换。例:

//数字:会从右到左三个三个的排列
 var num = 1234567;
 num.toLocaleString();//"1,234,567"
//日期: 格式化时间
 var date = new Date();
 date.toLocaleString();//"2020/2/13 下午11:14:42"

6.10.3 toJSON()方法

当使用JSON.stringify()序列化对象时,如果对象中有toJSON()方法时,JSON.stringify()方法会调用它。toJSON()的返回值就是序列化的结果,而不再是原来的对象。

//1.对象中没有toJSON()方法
var obj = {
     
	name:'xiaoming'
}
console.log(JSON.stringify(obj));//{"name":"ee"} 返回原对象

//2.对象中有toJSON()方法
var obj = {
     
	name:'xiaoming',
	toJSON(){
     
		return 'i am toJSON'
	}
}
console.log(JSON.stringify(obj));//"i am toJSON" 返回toJSON()方法的返回值

toJSON()方法参考文档

6.10.4 valueOf() 方法

valueOf()方法与toString()方法使用场景相同:当对象需要类型转换时

Q:怎样才能使对象类型转换?

以方法为例

(1)valueOf():

function person () {}
person.prototype.valueOf = ()=>{return ‘i am valueOf’}
var p = new person();
//当使用加法运算时
console.log(p + 1);//i am valueOf1 ,这里的p为valueOf返回的值

(2)toString()

function person () {}
person.prototype.toString = ()=>{return ‘i am toString’}
var p = new person();
//当使用alert输出时
alert§;//i am toString ,这里的p为toString返回的值

Q: 当对象里既有valueOf()又有toString()时,优先级是怎样的?

对于对象型参与 算术运算和 “==” 运算, 不等于比较元算(> 、<、>=、<=),自动发生数据类型转换,先调用 valueOf ,如果 valueOf 不能返回标量(number、string、boolean) 和 undefined、 null , 将继续调用 toString, 如果仍然返回对象型数据,报错。

Date 类型的例外: 在 + 和 == 运算中,优先 toString ,这应该是规范对该数据类型的特殊对待。

在界面输出中, 比如 alert() 和 document.write() ,将优先调用 toString,如果过得不到 标量 或 undefined、null ,再尝试 valueOf ,如果仍然返回对象则报错。

其实 parseInt()、 alert()、 document.write() 这些函数的调用中,参数所进行的类型转换,应当视为"被动的" , 是函数的实现方式使之优先调用 toString, 而非数据对象自动调用 toString。
比如 Number() 的参数类型转换就是优先调用 valueOf.

借用的参考文档:
valueOf()和toString()用法区别的参考文档
valueOf()和toString()用法区别具体例子的参考文档

你可能感兴趣的:(javascript)