公告栏

此网站主题为本人手写主题, 主题待开源···

音乐盒

站点信息

文章总数目: 308
已运行时间: 1187
目录
  1. 体系一:原型+原型链
    1. 隐式原型__proto__
    2. 显式原型prototype
    3. constructor构造函数
    4. instanceof
    5. 原型链和成员查找机制
    6. 原型体系中的继承
  2. 体系二:类(class)【ES6】
    1. 原型方法和原型字段声明
    2. 继承
    3. 多重继承
  3. 对象的各种创建方式
    1. 字面量
    2. 模式工厂
    3. 构造函数
    4. 原型模式
  4. 对象的内置方法
    1. Object.defineProperty
    2. 删除对象属性
    3. assign()
  5. 对象的遍历
    1. for...in
    2. Object.keys(obj)
  6. 参考
尼采般地抒情

尼采般地抒情

尼采般地抒情

公告栏

此网站主题为本人手写主题, 主题待开源···

站点信息

文章总数目: 308
已运行时间: 1187

前言:JavaScript首先在ES6没有出来之前,利用一个叫原型的一系列机制来用一段很长的代码来实现类的继承,说白了就是在函数里面默认给你加个一个叫原型的对象属性,再利用一系列指向来完成继承。在ES6之后,才有了形式上的类class及其对象,以及一个单词extends就搞定的继承,虽说搞定,但这里面的机制还是原型相关知识,记录学习一下。

不管是原型也好,新加的class也罢,就一个目的——为了实现面向对象。从两个体系来展开详述。

体系一:原型+原型链

隐式原型__proto__

每个对象里面都有__proto__属性,这个叫对象原型,这个玩意指向构造函数的prototype对象

__proto__对象原型的意义就在于为对象的查找机制提供一个方向,或者说一条路线,但是它是一个非标准属性,因此实际开发中,不可以使用这个属性,它只是内部指向原型对象 prototype

比如说,有一个Person类,有一个Student类,Student类继承自Person类,Student有一个实例student_1,那么student_1会有__proto__对象属性,并且展开该__proto__,会发现里面是Person类的方法和属性

显式原型prototype

每个构造函数里面都有一个属性,这个属性叫prototype,指向另一个对象有什么用?在后面原型链就会发现有用了),并且这个属性是一个对象,叫做构造函数原型

这样可以解决一个问题,就是创建不同实例,这些事例所用的方法都是同一个内存下的方法,实现共享

constructor构造函数

  1. 对象原型( __proto__)和构造函数(prototype)原型对象里面都有一个属性 constructor 属性 ,constructor 我们称为构造函数,因为它指回构造函数本身
  2. constructor 主要用于记录该对象引用于哪个构造函数,它可以让原型对象重新指向原来的构造函数。
  3. 一般情况下,对象的方法都在构造函数的原型对象中设置。如果有多个对象的方法,我们可以给原型对象采取对象形式赋值,但是这样就会覆盖构造函数原型对象原来的内容,这样修改后的原型对象 constructor  就不再指向当前构造函数了。此时,我们可以在修改后的原型对象中,添加一个 constructor 指向原来的构造函数。

instanceof

a instanceof b

判断是true还是false

看a的constructor是什么

当b为 a的constructor或a的__proto__的constructor……

结果都是true

原型链和成员查找机制

原型体系中的继承

call方法可以改变一个函数的指向

  1. 继承父构造函数里面的属性
// 1. 父构造函数
 function Father(uname, age) {
   // this 指向父构造函数的对象实例
   this.uname = uname;
   this.age = age;
 }
  // 2 .子构造函数 
function Son(uname, age, score) {
  // this 指向子构造函数的对象实例
  // 3.使用call方式实现子继承父的属性
  Father.call(this, uname, age);
  this.score = score;
}
var son = new Son('刘德华', 18, 100);
console.log(son);
  1. 继承方法
// 1. 父构造函数
function Father(uname, age) {
  // this 指向父构造函数的对象实例
  this.uname = uname;
  this.age = age;
}
Father.prototype.money = function() {
  console.log(100000);
 };
 // 2 .子构造函数 
  function Son(uname, age, score) {
      // this 指向子构造函数的对象实例
      Father.call(this, uname, age);
      this.score = score;
  }
// Son.prototype = Father.prototype;  这样直接赋值会有问题,如果修改了子原型对象,父原型对象也会跟着一起变化
  Son.prototype = new Father();
  // 如果利用对象的形式修改了原型对象,别忘了利用constructor 指回原来的构造函数
  Son.prototype.constructor = Son;
  // 这个是子构造函数专门的方法
  Son.prototype.exam = function() {
    console.log('孩子要考试');
  }
  var son = new Son('刘德华', 18, 100);
  console.log(son);

体系二:类(class)【ES6】

在 ES6 中新增加了类的概念,可以使用 class 关键字声明一个类,之后以这个类来实例化对象。类抽象了对象的公共部分,它泛指某一大类(class)对象特指某一个,通过类实例化一个具体的对象。其创建的方式和之前学过的语言很类似。

在 ES6 中类没有变量或是函数提升概念,所以必须先定义类,才能通过类实例化对象,这也是类和函数最大的不同。

原型方法和原型字段声明

原型方法:

  1. 构造函数方法
  2. get set
  3. 静态方法:通常作为类的工具函数
  4. 普通方法


原型字段:

  1. 私有字段
  2. 公有字段
class Tooltip {
  #test1 = 111; // 私有成员
  test2 = 222; // 公有成员
  static test3 = 333; // 静态成员(类内部不能访问 相当于类的属性)
  static fun1(a, b) {
    // 静态方法(类内部不能访问 相当于类的属性)
    return a + b;
  }
  constructor() {
    console.log('private member test1: ', ++this.#test1);
    console.log('public member test2: ', ++this.test2);
    console.log('origin class: ', this);
  }
}

class TextTooltip extends Tooltip {
  constructor(quill, options) {
    super(quill, options.bounds);
  }
}

this.textToolTip = new TextTooltip(quill, options);
console.log(this.textToolTip, 
            Tooltip.test3,
            TextTooltip.test3, 
            TextTooltip.fun1(333, 333));


export default TextTooltipToolbar;

继承

// 奥特曼类
class Aoteman {
    // 构造函数里面放共有属性、方法
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    Ability(abi) {
        console.log(this.name + " can " + abi);
    }
}

// 假 继承 奥特曼
class Jia extends Aoteman {
    constructor (x, y) {
        // 继承父类的构造函数
        super(x,y); 
        // 方便写自己的函数
        this.x = x;
        this.y = y;
    }
    // 自己内部的函数
    Chuiniu() {
        console.log(this.x + " chuiniu");
    }

}


// 创建迪迦对象
let dijia = new Aoteman('dijia', 100);
console.log(dijia);
dijia.Ability("X-ray");
let dijia_jia = new Jia("dijia_jia", 50);
dijia_jia.Ability("xxx");
dijia_jia.Chuiniu();

多重继承

JavaScript对象的继承只能继承一个父类,因为继承的根本实现是基于原型链的,所以继承不能同时指向多个对象,所以实现多重继承有两个思路:

  1. 父类链式继承
class Parent1 extends Parent2 {}
class Parent2 extends Parent3 {}
class Child extends Parent1 {}
  1. 实现Mixin来继承
function mixin(...mixins) {
  class Mixin {
    constructor(...args) {
      mixins.forEach(
        mixin => copyProperties(this, new mixin(...args)) // 拷贝实例属性
      ) 
    }
  }
  mixins.forEach(
    mixin => {
      copyProperties(Mixin, mixin); // 拷贝静态属性
      copyProperties(Mixin.prototype, mixin.prototype); // 拷贝原型属性
    }
  )

  return Mixin;
}

function copyProperties(target, source) {
  for (let key of Reflect.ownKeys(source)) {
    if (['constructor', 'prototype', 'name'].indexOf(key) < 0) {
      let desc = Object.getOwnPropertyDescriptor(source, key);
      Object.defineProperty(target, key, desc);
    }
  }
}
class Child extends mixin(Parent1, Parent2, Parent3) {}

对象的各种创建方式

字面量

属性和方法的调用:

属性可以用"."和["属性名"]来调用

方法用"."来调用

模式工厂

new一个空对象,let obj = new Object();

然后利用"."的方式给其添加属性和方法

内置的Object()构造函数

构造函数

构造函数:是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。

function 构造函数名(形参1,形参2,形参3) {
     this.属性名1 = 参数1;
     this.属性名2 = 参数2;
     this.属性名3 = 参数3;
     this.方法名 = 函数体;
}

let obj = new 构造函数名(实参1,实参2,实参3)


  • 构造函数约定首字母大写
  • 函数内的属性和方法前面需要添加 this ,表示当前对象的属性和方法。
  • 构造函数中不需要 return 返回结果
  • 当我们创建对象的时候,必须用 new 来调用构造函数

原型模式

下面详述什么是原型

对象的内置方法

参考教程:

Object.defineProperty

Object.defineProperty设置或修改对象中的属性

Object.defineProperty(对象,修改或新增的属性名,{
        value:修改或新增的属性的值,
        writable:true/false,//如果值为false 不允许修改这个属性值
        enumerable: false,//enumerable 如果值为false 则不允许遍历
    configurable: false  //configurable 如果为false 则不允许删除这个属性 属性是否可以被删除或是否可以再次修改特性
})

删除对象属性

assign()

  • Object.assign后者覆盖前者,再返回前者
  • 常用于深拷贝浅拷贝数据

对象的遍历

for...in

语句用于对数组或者对象的属性进行循环操作。

其语法如下:

for (变量 in 对象名字) {
    // 在此执行代码
}
  • 语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。书里面建议用const来加持。
for (let k in obj) {
    console.log(k);      // 这里的 k 是属性名
    console.log(obj[k]); // 这里的 obj[k] 是属性值
}

Object.keys(obj)

获取属性名

var obj = {
     id: 1,
     pname: '小米',
     price: 1999,
     num: 2000
};
var result = Object.keys(obj)
console.log(result)//[id,pname,price,num]

参考

评论区

Twikoo giscus