前端JavaScript中的class类

 更新时间:2021年10月22日 00:02  点击:2626 作者:onlythinking

1、类

类是用于创建对象的模板。JavaScript中生成对象实例的方法是通过构造函数,这跟主流面向对象语言(javaC# )写法上差异较大,如下:

function Point(x, y) {
  this.x = x;
  this.y = y;
}

Point.prototype.toString = function () {
  return '(' + this.x + ', ' + this.y + ')';
};

var p = new Point(1, 1);

ES6 提供了更接近Java语言的写法,引入了 Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。

如下:constructor()是构造方法,而this代表实例对象:

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

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

类的数据类型就是函数,它本身就是指向函数的构造函数:

// ES5 函数声明
function Point() {
 //...
}

// ES6 类声明
class Point {
  //....
  constructor() {
  }
}
typeof Point // "function"
Point === Point.prototype.constructor // true

在类里面定义的方法是挂到Point.prototype,所以类只是提供了语法糖,本质还是原型链调用。

class Point {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

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

Point.prototype = {
  //....
  toString()
}
var p = new Point(1, 1);
p.toString() // (1,1)

类的另一种定义方式类表达式

// 未命名/匿名类
let Point = class {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }
};
Point.name // Point

函数声明和类声明有个重要区别,函数声明会提升,类声明不会提升。

> let p = new Point(); // 被提升不会报错
> function Point() {}
> 
> let p = new Point(); // 报错,ReferenceError
> class Point {}
>

1.1 constructor()

constructor()方法是类的默认方法,new生成实例对象时会自动调用该方法。

一个类必须有constructor()方法,如果没有显式定义,引擎会默认添加一个空的constructor()

constructor()方法默认返回实例对象(即this)。

class Point {
}

// 自动添加
class Point {
  constructor() {}
}

1.2 getter和setter

ES5 一样,在类的内部可以使用getset关键字,对某个属性设置存值函数和取值函数,拦截该属性的存取行为。

class User {
  constructor(name) {
    this.name = name;
  }

  get name() {
    return this.name;
  }

  set name(value) {
    this.name = value;
  }
}

1.3 this

类的方法内部的this,它默认指向类的实例,在调用存在this的方法时,需要使用 obj.method()方式,否则会报错。

class User {
  constructor(name) {
    this.name = name;
  }
  printName(){
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
user.printName() // Name is jack
const { printName } = user;
printName()     // 报错 Cannot read properties of undefined (reading 'name')

如果要单独调用又不报错,一种方法可以在构造方法里调用bind(this)

class User {
  constructor(name) {
    this.name = name;
    this.printName = this.printName.bind(this);
  }
  printName(){
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
const { printName } = user;
printName()     // Name is jack

bind(this) 会创建一个新函数,并将传入的this作为该函数在调用时上下文指向。

另外可以使用箭头函数,因为箭头函数内部的this总是指向定义时所在的对象。

class User {
  constructor(name) {
    this.name = name;
  }
  printName = () => {
    console.log('Name is ' + this.name)
  }
}
const user = new User('jack')
const { printName } = user;
printName()     // Name is jack

1.4 静态属性

静态属性指的是类本身的属性,而不是定义在实例对象this上的属性。

class User {
}

User.prop = 1;
User.prop // 1

1.5 静态方法

可以在类里面定义静态方法,该方法不会被对象实例继承,而是直接通过类来调用。

静态方法里使用this是指向类。

class Utils {
  static printInfo() {
     this.info();
  }
  static info() {
     console.log('hello');
  }
}
Utils.printInfo() // hello

关于方法的调用范围限制,比如:私有公有,ES6暂时没有提供,一般是通过约定,比如:在方法前面加下划线_print()表示私有方法。

2、继承

Java中通过extends实现类的继承。ES6中类也可以通过extends实现继承。

继承时,子类必须在constructor方法中调用super方法,否则新建实例时会报错。

class Point3D extends Point {
  constructor(x, y, z) {
    super(x, y); // 调用父类的constructor(x, y)
    this.z = z;
  }

  toString() {
    return super.toString() + '  ' + this.z ; // 调用父类的toString()
  }
}

父类的静态方法,也会被子类继承

class Parent {
  static info() {
    console.log('hello world');
  }
}

class Child extends Parent {
}

Child.info()  // hello world

2.1 super关键字

在子类的构造函数必须执行一次super函数,它代表了父类的构造函数。

class Parent {}

class Child extends Parent {
  constructor() {
    super();
  }
}

在子类普通方法中通过super调用父类的方法时,方法内部的this指向当前的子类实例。

class Parent {
  constructor() {
    this.x = 1;
    this.y = 10
  }
  printParent() {
    console.log(this.y);
  }
  print() {
    console.log(this.x);
  }
}

class Child extends Parent {
  constructor() {
    super();
    this.x = 2;
  }
  m() {
    super.print();
  }
}

let c = new Child();
c.printParent() // 10
c.m() // 2

2.2 _proto_和prototype

初学JavaScript时, _proto_prototype 很容易混淆。首先我们知道每个JS对象都会对应一个原型对象,并从原型对象继承属性和方法。

  • prototype 一些内置对象和函数的属性,它是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。
  • _proto_ 每个对象都有这个属性,一般指向对应的构造函数的prototype属性。

下图是一些拥有prototype内置对象:

根据上面描述,看下面代码

var obj = {} // 等同于 var obj = new Object()

// obj.__proto__指向Object构造函数的prototype
obj.__proto__ === Object.prototype // true 

// obj.toString 调用方法从Object.prototype继承
obj.toString === obj.__proto__.toString // true

// 数组
var arr = []
arr.__proto__ === Array.prototype // true

对于function对象,声明的每个function同时拥有prototype__proto__属性,创建的对象属性__proto__指向函数prototype,函数的__proto__又指向内置函数对象(Function)的prototype

function Foo(){}
var f = new Foo();
f.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true

2.3 继承中的__proto__

类作为构造函数的语法糖,也会同时有prototype属性和__proto__属性,因此同时存在两条继承链。

  • 子类的__proto__属性,表示构造函数的继承,总是指向父类。
  • 子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。

class Parent {
}

class Child extends Parent {
}

Child.__proto__ === Parent // true
Child.prototype.__proto__ === Parent.prototype // true

2.4 继承实例中的__proto__

子类实例的__proto__属性,指向子类构造方法的prototype

子类实例的__proto__属性的__proto__属性,指向父类实例的__proto__属性。也就是说,子类的原型的原型,是父类的原型。

class Parent {
}

class Child extends Parent {
}

var p = new Parent();
var c = new Child();

c.__proto__ === p.__proto__ // false
c.__proto__ === Child.prototype // true
c.__proto__.__proto__ === p.__proto__ // true

3、小结

到此这篇关于前端JavaScript中的class类的文章就介绍到这了,更多相关JavaScript中的class内容请搜索猪先飞以前的文章或继续浏览下面的相关文章希望大家以后多多支持猪先飞!

原文出处:https://www.onlythinking.com/2021/10/19/%E5%89%8D%E7%AB%AF-j

[!--infotagslink--]

相关文章

  • 使用PHP+JavaScript将HTML页面转换为图片的实例分享

    这篇文章主要介绍了使用PHP+JavaScript将HTML元素转换为图片的实例分享,文后结果的截图只能体现出替换的字体,也不能说将静态页面转为图片可以加快加载,只是这种做法比较interesting XD需要的朋友可以参考下...2016-04-19
  • 关于JavaScript中name的意义冲突示例介绍

    在昨天的《Javascript权威指南》学习笔记之十:ECMAScript 5 增强的对象模型一文中,对于一段代码的调试出现了一个奇怪现象,现将源代码贴在下面: 复制代码 代码如下: <script type="text/javascript"> function Person(){}...2014-05-31
  • C#和JavaScript实现交互的方法

    最近做一个小项目不可避免的需要前端脚本与后台进行交互。由于是在asp.net中实现,故问题演化成asp.net中jiavascript与后台c#如何进行交互。...2020-06-25
  • javascript自定义的addClass()方法

    复制代码 代码如下: //element:需要添加新样式的元素,value:新的样式 function addClass(element, value ){ if (!element.className){ element.className = value; }else { newClassName = element.className; newClas...2014-05-31
  • JavaScript中的this关键字使用方法总结

    在javascritp中,不一定只有对象方法的上下文中才有this, 全局函数调用和其他的几种不同的上下文中也有this指代。 它可以是全局对象、当前对象或者任意对象,这完全取决于函数的调用方式。JavaScript 中函数的调用有以下...2015-03-15
  • JavaScript中逗号运算符介绍及使用示例

    有一道js面试题,题目是这样的:下列代码的执行结果是什么,为什么? 复制代码 代码如下: var i, j, k; for (i=0, j=0; i<10, j<6; i++, j++) { k = i+j; } document.write(k); 答案是显示10,这道题主要考察JavaScript的逗...2015-03-15
  • javascript的事件触发器介绍的实现

    事件触发器从字面意思上可以很好的理解,就是用来触发事件的,但是有些没有用过的朋友可能就会迷惑了,事件不是通常都由用户在页面上的实际操作来触发的吗?这个观点不完全正确,因为有些事件必须由程序来实现,如自定义事件,jQue...2014-06-07
  • 详解javascript数组去重问题

    首先,我想到的是另建一个结果数组,用来存储原始数组中不重复的数据。遍历原始数组依次跟结果数组中的元素进行比较,检测是否重复。于是乎,我写出了如下代码A: Array.prototype.clearRepetitionA = function(){ var resul...2015-11-08
  • PHP Fatal error: Cannot use object of type stdClass as array in错误

    下面一起来看看在php开发中碰到PHP Fatal error: Cannot use object of type stdClass as array in错误问题的解决办法吧。 普通的数组出现如下错误 代码...2016-11-25
  • ActiveX控件与Javascript之间的交互示例

    1、ActiveX向Javascript传参 复制代码 代码如下: <script language="javascript" for="objectname" event="fun1(arg)"> fun2(arg); </script> objectname为ActiveX控件名,通过<object>标签里的id属性设定,如下; 复制...2014-06-07
  • Javascript类型转换的规则实例解析

    这篇文章主要介绍了Javascript类型转换的规则实例解析,涉及到javascript类型转换相关知识,对本文感兴趣的朋友一起学习吧...2016-02-27
  • JavaScript获取浏览器信息的方法

    Window有navigator对象让我们得知浏览器的全部信息.我们可以利用一系列的API函数得知浏览器的信息.JavaScript代码如下:function message(){ txt = "<p>浏览器代码名: " + navigator.appCodeName + "</p>";txt+= "<p>...2015-11-24
  • 详解JavaScript操作HTML DOM的基本方式

    通过 HTML DOM,可访问 JavaScript HTML 文档的所有元素。 HTML DOM (文档对象模型) 当网页被加载时,浏览器会创建页面的文档对象模型(Document Object Model)。 HTML DOM 模型被构造为对象的树: 通过可编程的对象模型,Java...2015-10-23
  • 跟我学习javascript的最新标准ES6

    虽然ES6都还没真正发布,但已经有用ES6重写的程序了,各种关于ES789的提议已经开始了,这你敢信。潮流不是我等大众所能追赶的。潮流虽然太快,但我们不停下学习的步伐,就不会被潮流丢下的,下面来领略下ES6中新特性,一堵新生代JS...2015-11-24
  • javascript设计模式之解释器模式详解

    神马是“解释器模式”?先翻开《GOF》看看Definition:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。在开篇之前还是要科普几个概念: 抽象语法树: 解释器模式并未解释如...2014-06-07
  • JavaScript操作URL的相关内容集锦

    ---恢复内容开始---1.location.href.....(1)self.loction.href="http://www.cnblogs.com/url" window.location.href="http://www.cnblogs.com/url" 以上两个用法相同均为在当前页面打开URL页面 (2)this.locati...2015-10-30
  • javascript实现tab切换的四种方法

    tab切换在网页中很常见,故最近总结了4种实现方法。 首先,写出tab的框架,加上最简单的样式,代码如下: <!DOCTYPE html> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><style> *{ pa...2015-11-08
  • 基于JavaScript如何实现私有成员的语法特征及私有成员的实现方式

    前言在面向对象的编程范式中,封装都是必不可少的一个概念,而在诸如 Java,C++等传统的面向对象的语言中, 私有成员是实现封装的一个重要途径。但在 JavaScript 中,确没有在语法特性上对私有成员提供支持, 这也使得开发人员使...2015-10-30
  • JavaScript预解析,对象详解

    这篇文章主要介绍了JavaScript预解析,对象的的相关资料,小编觉得这篇文章写的还不错,需要的朋友可以参考下,希望能够给你带来帮助...2021-11-10
  • javascript实现数独解法

    生生把写过的java版改成javascript版,第一次写,很不专业,见谅。唉,我是有多闲。复制代码 代码如下: var Sudoku = { init: function (str) { this.blank = []; this.fixed = []; this.cell =...2015-03-15