JavaScript 面向对象编程

news2024/11/24 21:07:50
  • js 实例对象与 new 命令
  • js 对象的继承
  • es6 class
  • es6 class的继承

1 面向对象编程

  • 面向对象编程(Object Oriented Programming,缩写为 OOP)是目前主流的编程范式。

  • 它将真实世界各种复杂的关系,抽象为一个个对象,然后由对象之间的分工与合作,完成对真实世界的模拟。

  • 典型的面向对象编程语言(比如 C++ 和 Java),都有“类”(class)这个概念。

  • 所谓“类”就是对象的模板,对象就是“类”的实例。

  • 但是,JavaScript 语言的对象体系,不是基于“类”的,而是基于构造函数(constructor)和原型链(prototype)。

  • 对象

    • 对象是单个实物的抽象
    • 对象是一个容器,封装了属性(property)和方法(method)

1.1 生成实例对象——构造函数

JavaScript 语言中,生成实例对象的传统方法是通过构造函数。

// 定义构造函数 Point,该函数内有属性 x 和 y
function Point(x, y) {
  this.x = x;
  this.y = y;
}

// Object.prototype.toString():返回当前对象对应的字符串形式。(Point 函数 也是一种对象)
Point.prototype.toString = function () {
  return "(" + this.x + ", " + this.y + ")";
};

// 执行构造函数 Point(1, 2),返回一个实例对象 p, 内有属性 x = 1 和 y = 2
var p = new Point(1, 2);

在这里插入图片描述

1.1.1 构造函数

  • 就是专门用来生成实例对象的函数。它就是对象的模板,描述实例对象的基本结构。

  • 构造函数就是一个普通的函数,但具有自己的特征和用法。所以不用new也可以执行

  • 为了与普通函数区别,构造函数名字的第一个字母通常大写。

  • 特点:

    • 函数体内部使用了this关键字,代表了所要生成的对象实例。
    • 生成对象的时候,必须使用new命令。
  • ES5 的写法,toString()方法是可枚举的

Object.keys(Point.prototype); // ["toString"]
Object.getOwnPropertyNames(Point.prototype); // ["constructor","toString"]

1.1.2 new

  • new命令:执行构造函数,返回一个实例对象。

    • 使用new命令时,根据需要,构造函数也可以接受参数。
    • 如果忘了使用new命令,直接调用构造函数,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。
    • 为了保证构造函数必须与new命令一起使用,
    • 构造函数内部使用严格模式,即第一行加上use strict。这样的话,一旦忘了使用new命令,直接调用构造函数就会报错。
    • 构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。
  • new命令原理

    1. 创建一个空对象,作为将要返回的对象实例。
    2. 将这个空对象的原型,指向构造函数的prototype属性。
    3. 将这个空对象赋值给函数内部的this关键字。
    4. 开始执行构造函数内部的代码。

1.1.3 this

  • 构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。
  • 构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子。

1.1.4 返回

  • 如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;
  • 否则,就会不管return语句,返回this对象。
  • 另一方面,如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。
  • 因为new命令总是返回一个对象,要么是实例对象,要么是return语句指定的对象。若return语句返回的是字符串,new命令就会忽略该语句。

1.1.5 属性

  • new.target:函数内部可以使用new.target属性。如果当前函数是new命令调用,new.target指向当前函数,否则为undefined
  • 使用这个属性,可以判断函数调用的时候,是否使用new命令。

1.1.6 现有的对象作为模板,生成新的实例对象

  • 现有的对象作为模板,生成新的实例对象,使用Object.create()方法。因为有时拿不到构造函数,只能拿到一个现有的对象

1.2 生成实例对象——Class 类

ES6 提供了更接近传统语言的写法,引入了 Class(类)这个概念,作为对象的模板。

class Point {
  // 构造方法
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  toString() {
    return "(" + this.x + ", " + this.y + ")";
  }
}

var p = new Point(1, 2);

typeof Point; // "function"
Point === Point.prototype.constructor; // true

在这里插入图片描述

1.2.1 类

  • 生成对象的时候,必须使用new命令。
  • 类的数据类型就是函数,类本身就指向构造函数。
  • 类的所有方法都定义在类的prototype属性上面,所以类的新方法可加在prototype对象上面,Object.assign()一次向类添加多个方法。
Object.assign(Point.prototype, {
  toString() {},
  toValue() {},
});
  • 类的内部所有定义的方法,都是不可枚举的(non-enumerable),这与 ES5 不同
Object.keys(Point.prototype); // []
Object.getOwnPropertyNames(Point.prototype); // ["constructor","toString"]

1.2.2 方法

  • constructor()
    • 类的默认方法,通过new命令生成对象实例时,自动调用该方法。
    • 一个类必须有constructor()方法,如果没有显式定义,一个空的constructor()方法会被默认添加。
    • constructor()方法默认返回实例对象(即this),完全可以指定返回另外一个对象。
class Foo {
  constructor() {
    return Object.create(null);
  }
}

new Foo() instanceof Foo; // false
  • 类必须使用new调用,否则会报错。这是它跟普通构造函数的一个主要区别,后者不用new也可以执行。
class Foo {
  constructor() {...}
}

Foo() // TypeError: Class constructor Foo cannot be invoked without 'new'

1.3 对象的继承——构造函数

让一个构造函数继承另一个构造函数

  1. 子类继承父类的实例:在子类的构造函数中,调用父类的构造函数
  2. 子类继承父类的原型:让子类的原型指向父类的原型
// 定义构造函数 Shape
function Shape() {
  this.x = 0;
  this.y = 0;
}

// 定义方法 move
Shape.prototype.move = function (x, y) {
  this.x += x;
  this.y += y;
  console.info("Shape moved.");
};

Rectangle构造函数继承Shape

// 第一步,子类继承父类的实例
function Rectangle() {
  // 调用父类构造函数
  Shape.call(this); // 子类是整体继承父类。
}

// 另一种写法
function Rectangle() {
  this.base = Shape;
  this.base();
}

// 第二步,子类继承父类的原型
// 现有的对象作为模板,生成新的实例对象,使用`Object.create()`方法。因为有时拿不到构造函数,只能拿到一个现有的对象
// 子类的原型要赋值为`Object.create(Shape.prototype)`,而不是直接等于`Shape.prototype`。
// 否则后面一行对`Rectangle.prototype`的操作,会连父类的原型`Shape.prototype`一起修改掉。
Rectangle.prototype = Object.create(Shape.prototype);
Rectangle.prototype.constructor = Rectangle;

// 另外一种写法,是 Rectangle.prototype 等于一个父类实例。
// 这种写法也有继承的效果,但是子类会具有父类实例的方法。有时可能不是我们需要的,所以不推荐使用这种写法
Rectangle.prototype = new Shape();

采用这样的写法以后,instanceof运算符会对子类和父类的构造函数,都返回true

var rect = new Rectangle();

rect instanceof Rectangle; // true
rect instanceof Shape; // true

有时只需要单个方法的继承

ClassB.prototype.print = function () {
  ClassA.prototype.print.call(this);
  // some code
};
// 上面代码中,子类`B`的`print`方法先调用父类`A`的`print`方法,再部署自己的代码。这就等于继承了父类`A`的`print`方法。

1.4 对象的继承——class 类

Class 可以通过extends关键字实现继承,让子类继承父类的属性和方法。

class Point {
  /* ... */
}

// 子类 ColorPoint 继承 Point 类的所有属性和方法
class ColorPoint extends Point {
  constructor(x, y, color) {
    super(x, y); // 调用父类的constructor(x, y)
    this.color = color;
  }

  toString() {
    return this.color + " " + super.toString(); // 调用父类的toString()
  }
}
  • super关键字表示父类的构造函数,用来新建一个父类的实例对象。

  • ES6 规定,子类必须在constructor()方法中调用super(),否则就会报错。

    • 这是因为子类自己的this对象,必须先通过父类的构造函数完成塑造,得到与父类同样的实例属性和方法,然后再对其进行加工,添加子类自己的实例属性和方法。
    • 如果不调用super()方法,子类就得不到自己的this对象。
  • 为什么子类的构造函数,一定要调用super()?

    • 原因就在于 ES6 的继承机制,与 ES5 完全不同。
    • ES5 的继承机制,是先创造一个独立的子类的实例对象,然后再将父类的方法添加到这个对象上面,即“实例在前,继承在后”。
    • ES6 的继承机制,则是先将父类的属性和方法,加到一个空的对象上面,然后再将该对象作为子类的实例,即“继承在前,实例在后”。
    • 这就是为什么 ES6 的继承必须先调用super()方法,因为这一步会生成一个继承父类的this对象,没有这一步就无法继承父类。
  • 注意,这意味着新建子类实例时,父类的构造函数必定会先运行一次。

class Foo {
  constructor() {
    console.log(1);
  }
}

class Bar extends Foo {
  constructor() {
    super();
    console.log(2);
  }
}

const bar = new Bar();
// 1
// 2
// 子类构造函数调用`super()`时,会执行一次父类构造函数
  • 在子类的构造函数中,只有调用super()之后,才可以使用this关键字,否则会报错。

    • 这是因为子类实例的构建,必须先完成父类的继承,只有super()方法才能让子类实例继承父类。
  • 如果子类没有定义constructor()方法,这个方法会默认添加,并且里面会调用super()

  • 也就是说,不管有没有显式定义,任何一个子类都有constructor()方法。

class ColorPoint extends Point {}

// 等同于
class ColorPoint extends Point {
  constructor(...args) {
    super(...args);
  }
}
// 实例对象`cp`同时是`ColorPoint`和`Point`两个类的实例,这与 ES5 的行为完全一致。
let cp = new ColorPoint(25, 8, "green");

cp instanceof ColorPoint; // true
cp instanceof Point; // true

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/333657.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

第四章.误差反向传播法—ReLU/Sigmoid/Affine/Softmax-with-Loss层的实现

第四章.误差反向传播法 4.2 ReLU/Sigmoid/Affine/Softmax-with-Loss层的实现 1.ReLU层 1).公式 2).导数&#xff1a; 3).计算图&#xff1a; 4).实现&#xff1a; class ReLU:def __init__(self):self.mask None# 正向传播def forward(self, x):self.mask (x < 0) # 输入…

【深度学习基础7】预训练、激活函数、权重初始化、块归一化

一、Unsupervised Pre-training 得益于 Hinton and Salakhutdinov 在 2006 年的开创性工作— 无监督预训(unsupervised pre-training);在《Reducing the dimensionality of data with neural networks.》这篇论文中,他们在 RBMs 中引入无监督预训练,下面我们将在Autoenco…

RapperBot僵尸网络最新进化:删除恶意软件后仍能访问主机

自 2022 年 6 月中旬以来&#xff0c;研究人员一直在跟踪一个快速发展的 IoT 僵尸网络 RapperBot。该僵尸网络大量借鉴了 Mirai 的源代码&#xff0c;新的样本增加了持久化的功能&#xff0c;保证即使在设备重新启动或者删除恶意软件后&#xff0c;攻击者仍然可以通过 SSH 继续…

Qml学习——基本控件

最近在学习Qml&#xff0c;但对Qml的各种用法都不太熟悉&#xff0c;总是会搞忘&#xff0c;所以写几篇文章对学习过程中的遇到的东西做一个记录。 学习参考视频&#xff1a;https://www.bilibili.com/video/BV1Ay4y1W7xd?p1&vd_source0b527ff208c63f0b1150450fd7023fd8 目…

电视剧《狂飙》数据分析,正片有效播放市场占有率达65.7%

哈喽大家好&#xff0c;春节已经过去了&#xff0c;朋友们也都陆陆续续开工了&#xff0c;小编在这里祝大家开工大吉&#xff01;春节期间&#xff0c;一大批电视剧和网剧上映播出&#xff0c;其中电视剧《狂飙》以不可阻挡之势成功成为“开年剧王”。这里小编整理了一些《狂飙…

数据存储技术复习(三)未完

module4智能存储系统是功能丰富且可提供高度优化的I/o处理能力的RAID阵列。请绘制智能存储系统架构&#xff0c;并说明其各个关键组件的主要功能。前端缓存后端物理磁盘2&#xff0e;智能存储系统中&#xff0c;使用缓存进行的写入操作与直接写入到磁盘相比&#xff0c;可以带来…

2023年房地产投资-折价因子研究报告

一、折价因子分析 1.户型不好 一些楼盘的户型不是很理想&#xff0c;可能存在格局与面积分配不合理&#xff0c;浪费面积过多的情况。比如&#xff1a;入户无玄关、入户门正对卫生间、厨房卫生间没窗、长走廊、局部空间太小…… 2.楼层不合适&#xff0c;采光差 非电梯房的…

设计模式(七)----创建型模式之建造者模式

1、概述 将一个复杂对象的构建与表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 分离了部件的构造(由Builder来负责)和装配(由Director负责)。 从而可以构造出复杂的对象。这个模式适用于&#xff1a;某个对象的构建过程复杂的情况。 由于实现了构建和装配的解…

【本地项目】上传到【GitLab】流程详解

文章目录1、安装Git2、创建GitLab项目文件夹3、创建密钥4、向GitLab上传项目注意&#xff1a;本篇文章中提到的上传流程所需要的命令&#xff0c;几乎在GitLab的Command line instructions中都有所记载 1、安装Git 具体安装流程这里不做过多说明&#xff0c;安装流程可以参考…

JavaEE进阶第四课:Bean 作用域和生命周期

上篇文章介绍了Spring更简单的对象存储和取出&#xff0c;这篇文章我们将会介绍Bean 作用域和生命周期 目录1.作用域1.1引例1.2Bean的六种作用域1.3设置作用域2.生命周期2.1Spring 执行流程2.2Bean的生命周期结束语1.作用域 1.1引例 首先这里的作用域和我们之前java学到变量的…

2023-02-09 - 3 Java客户端的使用

1 Java客户端的使用 为了演示RestHighLevelClient的使用&#xff0c;需要创建一个Spring Boot Web项目。该项目的依赖配置如下&#xff1a; <dependencies> <!--Spring Boot Web依赖--> <dependency> <groupId>org.springframework.boot</gro…

tcp的理解

1、源端口号&#xff1a;发送方端口号2、目的端口号&#xff1a;接收方端口号3、序列号&#xff1a;报文段的数据的第一个字节的序号3、确认序号&#xff1a;期望收到对方下一个报文段的第一个数据字节的序号4、首部长度(数据偏移)&#xff1a;TCP报文段的数据起始距离TCP报文段…

List、ArrayList与顺序表的介绍(数据结构系列3)

目录 前言&#xff1a; 1.List 1.1什么是List 1.2List的使用 2.ArrayList 2.1线性表 2.2ArrayList的方法 2.3ArrayList的模拟实现 2.4ArrayList的使用 2.5ArrayList的三种遍历方式 2.5.1for循环遍历 2.5.2for-each遍历 2.5.3使用迭代器遍历 结束语&#xff1a; 前…

分享88个JS焦点图代码,总有一款适合您

分享88个JS焦点图代码&#xff0c;总有一款适合您 88个JS焦点图代码下载链接&#xff1a;https://pan.baidu.com/s/1zfspX9OSsbAlL53fjiSCEw?pwdulz6 提取码&#xff1a;ulz6 Python采集代码下载链接&#xff1a;https://wwgn.lanzoul.com/iKGwb0kye3wj base_url "…

XGBoost

目录 1.XGBoost推导示意图 2.分裂节点算法 Weighted Quantile Sketch 3.对缺失值得处理 1.XGBoost推导示意图 XGBoost有两个很不错得典型算法&#xff0c;分别是用来进行分裂节点选择和缺失值处理 2.分裂节点算法 Weighted Quantile Sketch 对于特征切点点得选择&#xff…

怎么不让消息弹出?录屏弹窗怎么关

当我们对电脑屏幕进行录制时&#xff0c;时不时跳出的消息窗口和广告会影响我们录制的效果。怎样不让消息弹出&#xff1f;如何关闭录屏弹窗&#xff1f;使用“锁定窗口录制”模式&#xff0c;就能很好地解决这个问题。那有没有拥有“锁定窗口”录制模式的录屏工具&#xff1f;…

synchronized 关键字-监视器锁 monitor lock

1.代码示例&#xff1a; package thread3;import java.util.Scanner;public class Test2 {public static Object object new Object();public static void main(String[] args) throws InterruptedException {Thread thread1 new Thread(() -> {Scanner scanner new Sca…

盂县基本情况

寒假的活动报告&#xff0c;万物皆可CSDN&#xff0c;贴一下吧 盂县隶属于阳泉市&#xff0c;阳泉市是李彦宏和刘慈欣的家乡&#xff0c;阳泉市内有百度云计算中心 基本情况 盂县&#xff0c;隶属山西省阳泉市&#xff0c;地处山西省东部、太行山西麓&#xff0c;东与河北省平…

测试开发面经

操作系统 进程与线程 进程间通信方式 进程间的六种通信方式 管道消息队列共享内存信号量信号套接字 socket长连接和短连接 长连接与短连接的概念&#xff1a;前者是整个通讯过程&#xff0c;客户端和服务端只用一个Socket对象&#xff0c;长期保持Socket的连接&#xff1b…

Windows/VM虚拟机安装黑群晖6.1-----保证有效而且简单操作

1视频&#xff1a;Windows/VM虚拟机安装黑群晖教程_哔哩哔哩_bilibili2:网址&#xff1a;Synology Web Assistant3&#xff1a;重新打开群晖操作步骤1&#xff1a;按着视频下载好资源后&#xff0c;按照视频操作&#xff0c;途中修改地方&#xff08;两个情况选择其中一个&…