JavaScript红宝书05-对象、类、面向对象编程(Objects, Classes, and Object-Oriented Programming)

38 阅读5分钟

理解对象

现代定义对象

let person = {
  name: 'js',
  age: 66,
  sayHello() {
    console.log(this.name, this.age);
  }
}

对象主要包含两种属性:数据属性(Data Properties)和存取属性(Accessor Properties)

数据属性

数据属性包含一个单独的数据空间,用于数据的读和取。数据属性有四个标志来描述描述它们的行为。

1.Configurable - 配置能力,属性是否被重新定义或者删除、改变属性标志,默认都是true,可直接改变。

2.Enumerable - 枚举能力,属性是否通过for-in循环遍历,默认是true直接遍历出来。

3.Writable - 写入能力,属性是否可改变,重新赋值,默认是true。

4.Value - 值,实际数据的存储位置,读取数据就从这里读取,默认是undefined。

基础练习(突然想起来的东西和本章无关,文科生学工总是不灵活,唉~)

  let obj = {
    name: 'naruto',
    age: 30,
    ninjitus:['lashgan','kageihunxin']
  }

  let js = JSON.stringify(obj) //对象转JSON字符串,这里只能对象,放JSON字符串就乱套了
  let jp = JSON.parse(js) //JSON字符串转为JS对象
  console.log(jp);

Object.defineProperty()

Object.defineProperty()方法可以配置属性的相关设置,writable设置false,可以禁止修改属性

let person = {
  
}

Object.defineProperty(person, 'name', {
  writable:false,
  value: '张三'
})

person.name = '法外狂徒'

console.log(person.name);

存取属性

存取属性:不包含属性值的,而包含属性的一对getter方法和setter方法。

存取属性也包含四个可设置想。有两个和数据属性相同设置项 Configurable和Enumerable不再赘述。不同的为Get和Set。

Get - 读取属性时会调用,默认undefined

Set - 写入属性时会调用,默认undefined

合并对象

在es6中引入了Object.assign()方法,这个方法可以接收一个目标对象,和多个源对象,并且把每个源对象拷贝过来,作为目标对象的属性

对象相等

在es6中判断对象是否相等通过 === 进行,也可以使用Object.is()方法进行判断,如:

console.log(Object.is('2', 2));
console.log(Object.is(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");

createPerson()方法在接收必要的参数后可以创建特定的对象,避免了创建同一类型对象,只是值不同产生的大量的冗余代码。

构造器模式

构造器:JavaScript原生的构造函数用于创建特定类型的对象,JavaScript也支持自定义构造器。

举例:

 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();
person2.sayName();

这段代码有三个特点

1.没有显示的创建对象

2.属性和方法都直接赋值到对象中

3.没有返回表达式

原型模式

每个方法都被原型属性创建,对象内部包含属性和方法,被特定类型的实例引用,可以直接通过prototype

栗子:

function Person() {}
      
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";

Person.prototype.sayName = function() {
  console.log(this.name);
 };
       
 let person1 = new Person();
 person1.sayName();
       
 let person2 = new Person();
 person2.sayName();  

原型模式特点

无论方法何时被创建,原型属性也会被创建,原型属性默认会获取构造器属性,比如Person.prototype.constructor会指向Person。当自定义构造器时,原型默认只会获取构造器属性,所有的方法都继承自Object。

继承

很多面向对象语言有,两种继承,一种是方法继承,一种是接口继承,JavaScript不存在接口继承,因为JavaScript不存在方法签名。

原型链

ECMA-262标准规定,在ECMAScript中,原型链作为主要的继承方法

原型链的缺点

原型链是继承能力强大的工具,但也存在问题,主要的问题就是关于原型的引用值的问题。

当使用原型实现继承时,原型实际上也会变成另一种类型的实例对象,这意味着曾经是原型属性,现在是实例对象的属性。

在ES6中已经可以使用Class关键字定义类了,可解决前面提到的问题

类的组成

包括:构造方法、实例方法、getter、setter和静态的类方法。

类的构造器

构造器关键字使用在类的定义区间使用,作为类的构造函数。使用方法名构造器,将会向指定的方法发送信号,用新的运算符创建新的实例。类中不是必须要定义构造器。

每次通过 new + 类名 创建对象,内部调用构造函数创建对象,新的创建对象会有属于自己的属性。没有限制新的实例里面添加什么,也没有限制以存在构造函数之后添加成员。

初始化

类初使用new运算符进行初始化会遵循以下几点

1.在内存中创建新的对象

2.这个新对象内部原型指向构造器的原型属性

3.这个构造器的值会赋值给新的对象

4.代码内部构造器会被执行

5.如果构造函数返回一个对象,那么new出来就会返回这个对象,否则会返回这个刚刚被创建的对象

原型方法和存取器

为了实例之间可以分享方法,类的语法定义运行方法在类颞部的原型上定义。

方法也可以定义在别的地方,但成员的数据,如私有和对象不能添加到原型上。

类方法与对象属性一直,这意味着,string、symbol和计算属性值可以作为key。

订阅发布

export default {
  datalist: [],
  subscribe(callback) {
    this.datalist.push(callback)
  },
  publish(value) {
    this.datalist.forEach(callback => {
      callback(value)
    })
  }
}