JS高级程序设计精简版(第八章:第八章对象、类与面向对象)附思维导图

        时隔两年后二刷JavaScript高级程序语言,纯手打读书笔记+思维导图,让自己有一个比较全面的知识体系,后面有遇到例子的时候会慢慢补充更多的用法。有不足之处欢迎大家评论区指出,共勉!!

        

一、对象的属性

  1. 定义属性

Object.defineProperty(obj,prop,desc) 或者Object.defineProperties(obj,{prop:{desc}})

desc是属性的配置,有六种,以下是其默认值。

value   get    set   默认值为undefined

writable  enumerable   configurable   //通过defineProperty定义的属性,这三个都默认为false,但object.name = ovv定义的都默认为true。

enumerable 可枚举:属性是否会出现在for in 或者 Object.keys()的遍历中

configrable  是否可以修改属性配置(除了writable为true时value可变,writable可以由true到false,或者,以及可否删除

2、属性的分类

1)数据属性:有保存数值的位置,没有set和get特性描述符。

2)访问器属性:不包含数值,没有writable和value,若无set则默认只读。

访问器属性只能通过defineProperty方法定义。

两种属性之间的转换是:只要添加了两种属性特有的描述符,就会自动转为哪种属性。

3、读取属性的特性

1)获取单个属性:

通过Object.getOwnPerpertyDescriptor(obj,prop)返回一个描述属性特性的对象desc,例如desc.value来获取属性的值,desc.enumerable获取是否可枚举。

2)获取全部属性:

通过Object.getOwnPerpertyDescriptor(obj)能够获取对象的全部属性的配置。{prop:{desc}}

4、合并对象

Object.assign()将每个对象中可枚举+自身属性复制到目标对象,通过get/set读写属性值,对值的复制是浅复制。

var result = Object.assign(obj1,obj2,obj3)   //三个对象的属性合并到Result对象中。

  • 对象相等

Object.is(a,b)解决了===的特殊情况,如在Object.is()中,+0,0相等,两个NaN相等。

  • 简写
  1. 属性名和值的变量名一样 name
  2. 计算属性名表达式  [getKeyName(nameKey)]
  3. 简写方法名  funName(){}
  1. 对象解构

let { name: newName, age,job=’111’} = person;   //将属性解构为变量,还可以赋初始值,用于当没有此属性时使用默认值。

二、创建对象☆

1、工厂模式

function createPerson(name) {

let o = new Object();

o.name = name;

return o;

}

工厂模式:函数内部new对象并返回,没有解决对象标识问题(对象是什么类型的)

  1. 构造函数模式

function Person(name){

this.name = name;

this.sayName = function(){}   //构造函数里的方法会在每个实例上都创建一遍,所以在这里可以把函数的定义挪到构造函数外部去。this.sayName = sayName(Person外部定义)

};

const obj = new Person(name)

构造函数的问题:外部定义方法会搞乱全局作用域,因为方法在全局定义却只会在obj内部调用,通过原型模式解决此问题。

  1. 原型模式

原型上定义的属性和方法可以被对象实例共享

可以通过原型对象字面量的形式,创建对象,注意要添加构造函数(完全修改原型)

缺点:①无法通过构造函数传参 ②原型上的数据是每个实例共享的,而非单独拥有。

  1. 组合使用构造模式+原型模式

原型对象写方法和constructor,构造函数中写属性。

  • 原型

函数Person:prototype属性,指向原型对象(Person.prototype)

原型对象Person.prototype:是一个普通的对象,有constructor(指向Person)+原型上的属性+方法。Person.prototype.isPrototypeOf(person1)//判断person1的__proto__是否指向此原型对象。

实例person:实例内部[[Prototype]]特性指向构造函数的原型对象(Person.prototype),但我们不能直接访问[[Prototype]],而是通过__proto__来访问。

Object.getPrototypeOf(),能够返回person的__proto__

获取实例自身属性person1.hasOwnProperty(name)

in操作符:可以单独使用或在for-in中循环使用。

单独用in:只要可以通过对象访问到的属性in都为true,无论原型还是实例本身。

for-in:可被枚举的属性(包括实例和原型)

Object.keys(person)  //数组:所有可枚举属性名

Object.getOwnPropertyNames(person)   //所有实例属性(包括不可枚举)

Object.getOwnPropertySymbols()  //所有实例属性(符号键名)

后面两个方法的枚举顺序是确定的:升序数值键名,插入顺序字符或符号键。

对象迭代:

Object.values()  //value的数组

Object.entries() // [key,value]的数组

原型注意:

  1. 原型对象字面量

可以通过对象字面量一次性对原型对象创建多个属性。但这样是重写了整个Person.propertype对象,因此要通过Object.defineProperty()来加一个不可枚举的constructor

  1. 动态性:

在原型上添加属性和方法,之前创建的实例也会相应的反应,因为指针已指向此对象。

但重写整个原型对象,由于[[Propertype]]是在调用构造函数时自动赋值的,所以之前创建的实例还是指向原来的原型对象,并不会做出修改。

  • 继承

原型链:即原型对象本身是另一个构造函数的实例,通过这样实现继承。

判断继承关系:①instanceof   ②Person.prototype.isPrototypeOf(obj)

  1. 原型链继承
  2. 盗用构造函数

3、组合继承(盗用构造函数 + 原型链)

盗用构造函数:实例属性不共享 + 构造函数传参

原型链:共享方法 + 实现继承

function SuperType(name){ //构造函数

this.name = name;

}

function SubType(name, age){ // 盗用构造函数:继承属性

SuperType.call(this, name);

this.age = age;

}

// 原型链:继承方法

SubType.prototype = new SuperType();

SubType.prototype.constructor = SubType; //修改构造器为SbType本身。

SubType.prototype.sayAge = function() {

console.log(this.age);

};

父类构造函数会调用两次:原型链继承(属性在原型对象上) + 盗用构造函数(属性在实例本身上,遮蔽了原型对象上的属性)

4、原型式继承

Object.create(新对象原型,desc)  //desc和defineProperty的desc一样,定义新增的属性。

适用于不需要单独创建构造函数的情况,与原型模式一样,需注意引用值的共享。

  1. 寄生式继承

function createAnother(original){ //要继承的对象

let clone = object(original); // 通过调用函数创建一个新对象

clone.sayHi = function() { // 以某种方式增强这个对象

console.log("hi");

};

return clone; // 返回这个对象

}

寄生式继承实现类似于工厂模式。它会使得函数无法重用,类似构造函数模式。

  1. 寄生式组合继承

核心代码就是将组合继承中,创建原型链部分的代码替换为以下代码,即可实现只调用一次原型的构造函数。寄生式组合继承可以算是引用类型继承的最佳模式。

function inheritPrototype(subType, superType) {

let prototype = object(superType.prototype); // 创建对象

prototype.constructor = subType; // 修改构造器

subType.prototype = prototype;} // 赋值原型,实现原型链 

class关键词是es6新增的,可以定义类,但这是语法糖,实际还是原型和构造函数。

  1. 定义类

    class Person{}

const Person = class {}  //在{}块中可以通过Person.name获取类表达式的名称字符串。

类受块级作用域限制

  1. 类构造函数

constructor关键词 定义创建类的构造函数。

  1. 实例化过程

创建新对象-->[[prototype]]=Person.prototype-->this = obj-->执行构造函数返回obj

类构造函数必须使用new调用,而其他构造函数若不使用new调用,则为window调用。

2)把类当成一个特殊的函数

typeof Person  //function

类本身具有与普通构造函数一样的行为。通过类创建或者类的constructor创建一个对象,instancof是可以区分的。

let p1 = new Person();  //p1 instanceof Person  为True

let p2 = new Person.constructor();  //p2 instanceof Person.constructor 为True

3、类语法中的成员

  1. 实例成员:构造函数中this指向新创建的实例,可以为实例添自有属性。
  2. 原型方法:在类中定义的方法作为原型方法,也支持set/get访问器。
  3. 静态成员:static定义在类上,this引用类自身,静态成员执行不特定于实例的操作。
  4. 迭代器与生成器:在类定义中,可以将生成器定义在原型上(原型方法)或类上(static)

注意:不能在类块中给原型添加原始值或对象作为成员数据,但可以在类定义外添加(会数据共享)。

4、继承

1、继承基础

使用extends关键词可以继承类、普通的构造函数。(有[[Construct]]和原型的对象)

this的值会反应调用相应方法的实例或者类。

2、构造函数/HomeObject/super

1)super:

super在派生类的方法(构造函数、静态方法)中,用super引用类的原型。

调用super会调用父类的构造函数,可以传参,并将返回的实例赋值给this,不能在调用super之前引用this。

2)[[HomeObject]]

构造函数和静态方法有[[HomeObject]],指向定义该方法的对象,super则指向[[HomeObject]]的原型。

3)构造函数

若未定义构造函数,则实例化派生类时会将全部参数传入父类的构造函数中。

若定义了构造函数,则必须调用super或return一个对象。

  1. 抽象基类

抽象基类:可以供其他类继承,但本身不会被实例化。new.target保存通过new调用的类或函数,来实现抽象基类,还可以要求派生类必须定义某种方法。

// 抽象基类

class Vehicle {

constructor() {

if (new.target === Vehicle) { //抽象基类

throw new Error('Vehicle cannot be directly instantiated');

}

if (!this.foo) { //要求派生类必须定义foo方法

throw new Error('Inheriting class must define foo()');

}

console.log('success!');

}

}

  1. 继承内置类型

继承JS内置的类型,这些类型的方法有返回值时,会默认返回新的类型,可以如下修改。

class SuperArray extends Array { //继承内置类型

static get [Symbol.species]() { //修改方法返回类型为Array而非默认的SuperArray

return Array;

}

}

  1. 类混入

把不同的类集中到一个类中,区别与对象混入(Object.assign()),实现是在类表达式中混入多个对象元素,可以嵌套调用ABC三个类,但是很少使用混入模式,更多使用组合模式。

function mix(BaseClass, ...Mixins) {

return Mixins.reduce((accumulator, current) => current(accumulator), BaseClass);

}

class Bus extends mix(Vehicle, A, B, C) {}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值