《深入理解ES6》笔记—— JavaScript中的类class(9)
ES5中的近类结构
ES5以及之前的版本,没有类的概念,但是聪明的JavaScript开发者,为了实现面向对象,创建了特殊的近类结构。
ES5中创建类的方法:新建一个构造函数,定义一个方法并且赋值给构造函数的原型。
'use strict';
//新建构造函数,默认大写字母开头
function Person(name) {
this.name = name;
}
//定义一个方法并且赋值给构造函数的原型
Person.prototype.sayName = function () {
return this.name;
};
var p = new Person('eryue');
console.log(p.sayName() // eryue
);
ES6 class类
ES6实现类非常简单,只需要类声明。推荐 babel在线测试ES6 测试下面的代码。
类声明
如果你学过java,那么一定会非常熟悉这种声明类的方式。
class Person {
//新建构造函数
constructor(name) {
this.name = name //私有属性
}
//定义一个方法并且赋值给构造函数的原型
sayName() {
return this.name
}
}
let p = new Person('eryue')
console.log(p.sayName()) // eryue
和ES5中使用构造函数不同的是,在ES6中,我们将原型的实现写在了类中,但本质上还是一样的,都是需要新建一个类名,然后实现构造函数,再实现原型方法。
私有属性:在class中实现私有属性,只需要在构造方法中定义this.xx = xx。
类声明和函数声明的区别和特点
1、函数声明可以被提升,类声明不能提升。
2、类声明中的代码自动强行运行在严格模式下。
3、类中的所有方法都是不可枚举的,而自定义类型中,可以通过Object.defineProperty()手工指定不可枚举属性。
4、每个类都有一个[[construct]]的方法。
5、只能使用new来调用类的构造函数。
6、不能在类中修改类名。
类表达式
类有2种表现形式:声明式和表达式。
//声明式
class B {
constructor() {}
}
//匿名表达式
let A = class {
constructor() {}
}
//命名表达式,B可以在外部使用,而B1只能在内部使用
let B = class B1 {
constructor() {}
}
类是一等公民
JavaScript函数是一等公民,类也设计成一等公民。
1、可以将类作为参数传入函数。
//新建一个类
let A = class {
sayName() {
return 'eryue'
}
}
//该函数返回一个类的实例
function test(classA) {
return new classA()
}
//给test函数传入A
let t = test(A)
console.log(t.sayName()) // eryue
2、通过立即调用类构造函数可以创建单例。
let a = new class {
constructor(name) {
this.name = name
}
sayName() {
return this.name
}
}('eryue')
console.log(a.sayName()) // eryue
访问器属性
类支持在原型上定义访问器属性。
class A {
constructor(state) {
this.state = state
}
// 创建getter
get myName() {
return this.state.name
}
// 创建setter
set myName(name) {
this.state.name = name
}
}
// 获取指定对象的自身属性描述符。自身属性描述符是指直接在对象上定义(而非从对象的原型继承)的描述符。
let desriptor = Object.getOwnPropertyDescriptor(A.prototype, "myName")
console.log("get" in desriptor) // true
console.log(desriptor.enumerable) // false 不可枚举
可计算成员名称
可计算成员是指使用方括号包裹一个表达式,如下面定义了一个变量m,然后使用[m]设置为类A的原型方法。
let m = "sayName"
class A {
constructor(name) {
this.name = name
}
[m]() {
return this.name
}
}
let a = new A("eryue")
console.log(a.sayName()) // eryue
生成器方法
回顾一下上一章讲的生成器,生成器是一个返回迭代器的函数。在类中,我们也可以使用生成器方法。
class A {
*printId() {
yield 1;
yield 2;
yield 3;
}
}
let a = new A()
console.log(a.printId().next()) // {done: false, value: 1}
console.log(a.printId().next()) // {done: false, value: 2}
console.log(a.printId().next()) // {done: false, value: 3}
这个写法很有趣,我们新增一个原型方法稍微改动一下。
class A {
*printId() {
yield 1;
yield 2;
yield 3;
}
render() {
//从render方法访问printId,很熟悉吧,这就是react中经常用到的写法。
return this.printId()
}
}
let a = new A()
console.log(a.render().next()) // {done: false, value: 1}
静态成员
静态成员是指在方法名或属性名前面加上static关键字,和普通方法不一样的是,static修饰的方法不能在实例中访问,只能在类中直接访问。
class A {
constructor(name) {
this.name = name
}
static create(name) {
return new A(name)
}
}
let a = A.create("eryue")
console.log(a.name) // eryue
let t = new A()
console.log(t.create("eryue")) // t.create is not a function
继承与派生类
我们在写react的时候,自定义的组件会继承React.Component。
class A extends Component {
constructor(props){
super(props)
}
}
A叫做派生类,在派生类中,如果使用了构造方法,就必须使用super()。
class Component {
constructor([a, b] = props) {
this.a = a
this.b = b
}
add() {
return this.a + this.b
}
}
class T extends Component {
constructor(props) {
super(props)
}
}
let t = new T([2, 3])
console.log(t.add()) // 5
关于super使用的几点要求:
1、只可以在派生类中使用super。派生类是指继承自其它类的新类。
2、在构造函数中访问this之前要调用super(),负责初始化this。
class T extends Component {
constructor(props) {
this.name = 1 // 错误,必须先写super()
super(props)
}
}
3、如果不想调用super,可以让类的构造函数返回一个对象。
类方法遮蔽
我们可以在继承的类中重写父类的方法。
class Component {
constructor([a, b] = props) {
this.a = a
this.b = b
}
//父类的add方法,求和
add() {
return this.a + this.b
}
}
class T extends Component {
constructor(props) {
super(props)
}
//重写add方法,求积
add() {
return this.a * this.b
}
}
let t = new T([2, 3])
console.log(t.add()) // 6
静态成员继承
父类中的静态成员,也可以继承到派生类中。静态成员继承只能通过派生类访问,不能通过派生类的实例访问。
class Component {
constructor([a, b] = props) {
this.a = a
this.b = b
}
static printSum([a, b] = props) {
return a + b
}
}
class T extends Component {
constructor(props) {
super(props)
}
}
console.log(T.printSum([2, 3])) // 5
派生自表达式的类
很好理解,就是指父类可以是一个表达式。
内建对象的继承
有些牛逼的人觉得使用内建的Array不够爽,就希望ECMA提供一种继承内建对象的方法,然后那帮大神们就把这个功能添加到class中了。
class MyArray extends Array { }
let colors = new Array()
colors[0] = "1"
console.log(colors) // [1]
Symbol.species
该用法我还没有接触过,目前只知道在内建对象中使用了该方法,如果在类中调用this.constructor,使用Symbol.species可以让派生类重写返回类型。
在构造函数中使用new.target
new.target通常表示当前的构造函数名。通常我们使用new.target来阻止直接实例化基类,下面是这个例子的实现。
class A {
constructor() {
//如果当前的new.target为A类,就抛出异常
if (new.target === A) {
throw new Error("error haha")
}
}
}
let a = new A()
console.log(a) // error haha
总结
本章只有一个知识点,那就是class的使用,最开始的声明class,到后面的继承派生类,都是非常常用的写法,还有静态成员的使用。
如果上面的那些例子你练习的不够爽,或许你该找个react基础demo简单的使用class来练练手了。
《深入理解ES6》笔记—— JavaScript中的类class(9)的更多相关文章
- 【读书笔记】【深入理解ES6】#9-JavaScript中的类
大多数面向对象的编程语言都支持类和类继承的特性,而JavaScript却不支持这些特性,只能通过其他方法定义并关联多个相似的对象.这个状态一直从ECMAScript 1持续到ECMAScript 5. ...
- 理解和使用 JavaScript 中的回调函数
理解和使用 JavaScript 中的回调函数 标签: 回调函数指针js 2014-11-25 01:20 11506人阅读 评论(4) 收藏 举报 分类: JavaScript(4) 目录( ...
- 如何理解并学习javascript中的面向对象(OOP) [转]
如果你想让你的javascript代码变得更加优美,性能更加卓越.或者,你想像jQuery的作者一样,写出属于自己优秀的类库(哪怕是基于 jquery的插件).那么,你请务必要学习javascript ...
- JavaScript中创建类,赋值给ajax中的data参数
缘由:因为要给根据是否选中checkbox来动态增加ajax中data的属性(ajax的data属性格式的几种方法,参考http://www.jb51.net/article/46676.htm) d ...
- [转]理解与使用Javascript中的回调函数
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...
- 【JavaScript】理解与使用Javascript中的回调函数
在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用.既然函数实际上是对象:它们能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回. 因 ...
- JavaScript中的类
JavaScript类的相关知识 1.例子 /* 例1 */// 定义一个构造函数function Range(from, to){ this.from = from; this.to = ...
- Javascript中的类实现
Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的extend或冒号,它也没有用来支持虚函数的virtual,不过,Javascript是一门 ...
- JavaScript中定义类的方式详解
本文实例讲述了JavaScript中定义类的方式.分享给大家供大家参考,具体如下: Javascript本身并不支持面向对象,它没有访问控制符,它没有定义类的关键字class,它没有支持继承的exte ...
随机推荐
- Jquery.Validate清除验证信息|laydate时间控件无法清除validate提示问题
最近做一个需求,用到模态框和Jquery.Validate验证框架: 点击添加时弹出模态框,当输入数据保存时如果数据不能通过校验,则会触发Validate验证并显示提示信息: 如果此时关闭弹出层,下次 ...
- 使用Three.js实现神奇的3D文字悬浮效果
声明:本文涉及图文和模型素材仅用于个人学习.研究和欣赏,请勿二次修改.非法传播.转载.出版.商用.及进行其他获利行为. 背景 在 Three.js Journey 课程示例中,提供了一个使用 Thre ...
- Windows原理深入学习系列-特权
这是[信安成长计划]的第 21 篇文章 0x00 目录 0x01 介绍 0x02 结构分析 0x03 进程注入测试 0x04 参考文章 0x01 介绍 在 Token 当中还存在一个特别重要的内容-- ...
- netty搭建rpc框架
介绍 netty想必大家都不陌生,我就不废话介绍了...(主要是懒,网上资料很多的) 本文主要使用netty搭建rpc远程调用框架,实现了个注册中心微服务,整合了springboot例子... 开发内 ...
- laravel 解决跨域问题并封装到中间件
larav 官方手册有详细的步骤 https://learnku.com/articles/6504/laravel-cross-domain-solution 我们在用 laravel 进行开发的时 ...
- php 23种设计模型 - 模板方法模式
模板模式 模板模式准备一个抽象类,将部分逻辑以具体方法以及具体构造形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑.不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现.先制 ...
- 5. 堪比JMeter的.Net压测工具 - Crank 实战篇 - 接口以及场景压测
目录 堪比JMeter的.Net压测工具 - Crank 入门篇 堪比JMeter的.Net压测工具 - Crank 进阶篇 - 认识yml 堪比JMeter的.Net压测工具 - Crank 进阶篇 ...
- 2.4 C++STL deque容器详解
文章目录 2.4.1 引入 2.4.2 代码示例 2.4.3 代码运行结果 2.4.4 具体案例 总结 2.4.1 引入 deque容器类比vector容器来学习. deque为双向开口容器,见下图. ...
- JavaScript闭包的概念及用法
1.闭包的概念: 闭包就是能够读取其他函数内部变量的函数. 例如: function f1(){ var n=999; function f2(){ alert(n); } return f2; } ...
- 【面经】MyBatis常见面试问题
1.什么是 MyBatis? 答:MyBatis 是一个可以自定义 SQL.存储过程和高级映射的持久层框架. 2.讲下 MyBatis 的缓存 答:MyBatis 的缓存分为一级缓存和二级缓存,一级缓 ...