JavaScript高级程序设计| Ch8对象、类与面向对象编程 笔记

《JavaScript高级程序设计(第4版)》

8 对象、类与面向对象编程

由于这部分在《你不知道的JavaScript(上卷)》有记过笔记,因此本篇的相关内容略写

8.1 理解对象

创建自定义对象的通常方式是创建 Object 的一个新实例,然后再给它添加属性和方法。

8.1.1 属性的类型

1.数据属性

  • configurable
  • enumerable
  • writable
  • value

2.访问器属性
访问器属性不包含数据值。相反,它们包含一个获取(getter)函数和一个设置(setter)函数,不过这两个函数不是必需的。在读取访问器属性时,会调用获取函数。在写入访问器属性时,会调用设置函数并传入新值,这个函数必须决定对数据做出什么修改。

  • configurable
  • enumerable
  • get
  • set

8.1.2 定义多个属性

Object.defineProperties(要添加/修改属性的对象, 描述符对象)
描述符对象的属性与要添加/修改的属性一一对应。

8.1.3 读取属性的特性

Object.getOwnPropertyDescriptor(属性所在的对象. 要取得描述符的属性名)

let book = {
    
    }; 
Object.defineProperties(book, {
    
     
  year_: {
    
     
    value: 2017 
 }, 
  edition: {
    
     
    value: 1 
 }, 
  year: {
    
     
    get: function() {
    
     
      return this.year_; 
 }, 
    set: function(newValue){
    
     
       if (newValue > 2017) {
    
     
         this.year_ = newValue; 
         this.edition += newValue - 2017; 
       } 
     } 
  } 
}); 
let descriptor = Object.getOwnPropertyDescriptor(book, "year_"); 
console.log(descriptor.value); // 2017 
console.log(descriptor.configurable); // false 
console.log(typeof descriptor.get); // "undefined" 
let descriptor = Object.getOwnPropertyDescriptor(book, "year"); 
console.log(descriptor.value); // undefined 
console.log(descriptor.enumerable); // false 
console.log(typeof descriptor.get); // "function"

8.1.4 合并对象

merge/mixin
Object.assign(一个目标对象, 一个或多个源对象)然后将每个源对象中可枚举(Object.propertyIsEnumerable()返回 true)和自有(Object.hasOwnProperty()返回 true)属性复制到目标对象。
Object.assign()实际上对每个源对象执行的是浅复制。如果多个源对象都有相同的属性,则使用最后一个复制的值。

dest = {
    
    }; 
src = {
    
     id: 'src' }; 
result = Object.assign(dest, src); 
// Object.assign 修改目标对象
// 也会返回修改后的目标对象
console.log(dest === result); // true 
console.log(dest !== src); // true 
console.log(result); // { id: src } 
console.log(dest); // { id: src } 

8.1.5 对象标识及相等判定

《JavaScript高级程序设计(第4版)》

8.1.6 增强的对象语法

ES6 为定义和操作对象新增了很多极其有用的语法糖特性。这些特性都没有改变现有引擎的行为,但极大地提升了处理对象的方便程度。
1.属性值简写
《JavaScript高级程序设计(第4版)》
2.可计算属性
在引入可计算属性之前,如果想使用变量的值作为属性,那么必须先声明对象,然后使用中括号语法来添加属性。换句话说,不能在对象字面量中直接动态命名属性。例如:

const nameKey = 'name'; 
const ageKey = 'age'; 
const jobKey = 'job'; 

let person = {
    
    }; 
person[nameKey] = 'Matt'; 
person[ageKey] = 27; 
person[jobKey] = 'Software engineer'; 

console.log(person); // { name: 'Matt', age: 27, job: 'Software engineer' } 

有了可计算属性,就可以在对象字面量中完成动态属性赋值。中括号包围的对象属性键告诉运行时将其作为 JavaScript 表达式而不是字符串来求值:

const nameKey = 'name'; 
const ageKey = 'age'; 
const jobKey = 'job'; 

let person = {
    
     
 [nameKey]: 'Matt', 
 [ageKey]: 27, 
 [jobKey]: 'Software engineer' 
}; 

console.log(person); // { name: 'Matt', age: 27, job: 'Software engineer' } 

因为被当作 JavaScript 表达式求值,所以可计算属性本身可以是复杂的表达式,在实例化时再求值:

const nameKey = 'name'; 
const ageKey = 'age'; 
const jobKey = 'job'; 
let uniqueToken = 0; 

function getUniqueKey(key) {
    
     
 return `${
      
      key}_${
      
      uniqueToken++}`; 
} 

let person = {
    
     
 [getUniqueKey(nameKey)]: 'Matt', 
 [getUniqueKey(ageKey)]: 27, 
 [getUniqueKey(jobKey)]: 'Software engineer' 
}; 

console.log(person); // { name_0: 'Matt', age_1: 27, job_2: 'Software engineer' } 

3.简写方法名
《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》

8.1.7 对象解构

ES6新增了对象解构语法,可以在一条语句中使用嵌套数据实现一个或多个赋值操作。简单地说,对象解构就是使用与对象匹配的结构来实现对象属性赋值。
下面的例子展示了两段等价的代码,首先是不使用对象解构的:

// 不使用对象解构
let person = {
    
     
 name: 'Matt', 
 age: 27 
}; 

let personName = person.name, 
 personAge = person.age; 
 
console.log(personName); // Matt 
console.log(personAge); // 27

然后,是使用对象解构的:

// 使用对象解构
let person = {
    
     
 name: 'Matt', 
 age: 27 
}; 
let {
    
     name: personName, age: personAge } = person; 
console.log(personName); // Matt 
console.log(personAge); // 27 

《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》1.嵌套解构
《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》2.部分解构
《JavaScript高级程序设计(第4版)》3.参数上下文匹配
《JavaScript高级程序设计(第4版)》

8.2 创建对象

8.2.1 概述

ES5.1并没有正式支持面向对象的结构,比如类或继承。但是,正如接下来几节会介绍的,巧妙地运用原型式继承可以成功地模拟同样的行为。
ES6开始正式支持类和继承。ES6 的类旨在完全涵盖之前规范设计的基于原型的继承模式。不过,无论从哪方面看,ES6 的类都仅仅是封装了 ES5.1 构造函数加原型继承的语法糖而已。

8.2.2 工厂模式

用于抽象创建特定对象的过程
下例展示了一种按照特定接口创建对象的方式:

function createPerson(name, age, job) {
    
     
  let o = new Object(); 
  o.name = name; 
  o.age = age; 
  o.job = job; 
  o.sayName = function() {
    
     
    console.log(this.name); 
 }; 
  return o; 
} 
let person1 = createPerson("Nicholas", 29, "Software Engineer"); 
let person2 = createPerson("Greg", 27, "Doctor"); 

这种工厂模式虽然可以解决创建多个类似对象的问题,但没有解决对象标识问题(即新创建的对象是什么类型)

8.2.3 构造函数模式

function Person(name, age, job){
    
     
  this.name = name; 
  this.age = age; 
  this.job = job; 
  this.sayName = function() {
    
     
    console.log(this.name); 
  }; 
} 

let person1 = new Person("Nicholas", 29, "Software Engineer"); 
let person2 = new Person("Greg", 27, "Doctor"); 

person1.sayName(); // Nicholas 
person2.sayName(); // Greg 

与工厂模式相比,构造函数模式的区别:

  • 没有显示的创建对象
  • 属性和方法直接赋值给了this
  • 没有return
  • 按照惯例,构造函数名称的首字母都是要大写的,非构造函数则以小写字母开头。有助于在 ECMAScript 中区分构造函数和普通函数,ECMAScript 的构造函数就是能创建对象的函数。
  • 定义自定义构造函数可以确保实例被标识为特定类型

用new创建构造函数,调用构造函数后会执行如下操作

  1. 在内存中创建一个新对象
  2. 这个新对象内部的[[Prototype]]特性被赋值为构造函数的prototype属性
  3. 构造函数内部的this被赋值为这个新对象(即this指向新对象)
  4. 执行构造函数内部的代码(给新对象添加属性)
  5. 如果构造函数返回非空对象,则返回该对象;否则,返回刚创建的信对象
    《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》

8.2.4 原型模式

《JavaScript高级程序设计(第4版)》1.理解原型
无论何时,只要创建一个函数,就会按照特定的规则为这个函数创建一个 prototype 属性(指向
原型对象)。默认情况下,所有原型对象自动获得一个名为 constructor 的属性,指回与之关联的构造函数。
2.原型层级
link
3.原型和in操作符
《JavaScript高级程序设计(第4版)》《JavaScript高级程序设计(第4版)》4.属性枚举顺序

  • for-in 循环和 Object.keys()的枚举顺序是不确定的,取决于 JavaScript 引擎,可能因浏览器而异

  • Object.getOwnPropertyNames()、Object.getOwnPropertySymbols()和 Object.assign()的枚举顺序是确定性的。先以升序枚举数值键,然后以插入顺序枚举字符串和符号键。在对象字面量中定义的键以它们逗号分隔的顺序插入

8.2.5 对象迭代

1.其他原型语法
2.原型的动态性
3.原生对象原型
4.原型的问题

8.3 继承

很多面向对象语言都支持两种继承:接口继承和实现继承。
前者只继承方法签名,后者继承实际的方法。接口继承在 ECMAScript 中是不可能的,因为函数没有签名。实现继承是 ECMAScript 唯一支持的继承方式,而这主要是通过原型链实现的。
1.默认原型
2.原型与继承关系
3.关于方法
4.原型链问题

8.3.2 盗用构造函数

1.传递参数
2.盗用构造函数的问题

8.3.3 组合继承

8.3.4 原型式继承

8.3.5 寄生式继承

8.3.6 寄生式组合继承

8.4 类

ECMAScript 6 新引入的 class 关键字具有正式定义类的能力。类(class)是ECMAScript 中新的基础性语法糖结构。虽然 ECMAScript 6 类表面上看起来可以支持正式的面向对象编程,但实际上它背后使用的仍然是原型和构造函数的概念

8.4.1 类定义

8.4.2 类构造函数

1.实例化
2.把类当成特殊函数

8.4.3 实例、原型和类成员

1.实例成员
2.原型方法与访问器
3.静态类方法
4.非函数原型和类成员
5.迭代器与生成器方法

8.4.4 继承

1.继承基础
2.构造函数、HomeObject和super()
3.抽象基类
4.继承内置类型
5.类混入

猜你喜欢

转载自blog.csdn.net/qq_42376600/article/details/127250614