您好!
欢迎来到京东云开发者社区
登录
首页
博文
课程
大赛
工具
用户中心
开源
首页
博文
课程
大赛
工具
开源
更多
用户中心
开发者社区
>
博文
>
浅谈ES6之class
分享
打开微信扫码分享
点击前往QQ分享
点击前往微博分享
点击复制链接
浅谈ES6之class
京东ZERO团队
2021-01-07
IP归属:未知
25680浏览
Es6
# ES6-class基础 ### 一、class写法 在js中,传统的生成实例的方法是使用构造函数: ```javascript function Person(name) { this.name = name; } Person.say = function () { alert('Hi') } var bob = new Person('Bob'); ``` 在ES6中,引入了`class`的概念。class其实是个语法糖,因为class的绝大多数功能,在ES5中都能实现,class的写法是让对象原型的写法更加清晰,更符合面向对象的语法特点。 具体解释一下: * 首先声明了一个名字为Person的class,换做ES5的写法就是 function Person ( ) { }; * class里面写的方法,最终都定义在了 class 的原型上,换做ES5的写法就是:Person.prototype.say = function ( ) { }; * constructor 方法就是构造方法,里面的 this 代表实例对象,constructor 属性,直接指向'类'的本身; * constructor 是class的默认方法,通过 new 命令生成对象实例时,自动调用 constructor ,即使没有定义 constructor ,也会默认有一个空的 constructor; ### 二、class基础 #### 1.class内部所有定义的方法都是不可枚举的 ```javascript class Person { constructor(name) { this.name = name; } say () { alert('Hi') } } console.log(Object.keys(Person.prototype)) // [] ``` 但是ES5的构造函数中的方法是可枚举的: ```javascript function Person(name) { this.name = name; } Person.say = function () { alert('Hi') } console.log(Object.keys(Person.prototype)) // ['say'] ``` #### 2.constructor constructor是类的默认方法,在使用new生成对象实例时自动调用。一个类必须有constructor方法,若没有显示定义,则JS默认添加一个空的constructor方法: ```javascript class Point{} ``` ```javascript // 等同于 class Point{ constructor(){} } ``` 类必须使用new操作符调用,而构造函数可以直接使用: ```javascript class Point { constructor() { return Object.create(null); } } Point(); // Class constructor Point cannot be invoked without 'new' ``` #### 3.取值函数(getter)和存值函数(setter) 同ES5,在类的内部可以使用get和set关键字,set和get函数是设置在属性的Descriptor对象上的 ```javascript class Point{ constructor() { // ... } get x() { console.log('getter'); } set x(val) { console.log(`setter: ${val}`) } } const p = new Point(); p.x = 1; // setter: 1 p.x; // getter ``` #### 4.静态方法和静态属性 静态方法是指在方法前加上static关键字,表示该方法不会被继承,是直接通过类来调用的方法 ```javascript class Point { static classMethod(){ return 'hello'; } } let point = new Point() console.log(point.classMethod()) // Uncaught TypeError: point.classMethod is not a function console.log(Point.classMethod()) // hello ``` 静态属性指的是Class本身的属性,即Class.propName,而不是定义在实例对象(即this)上的属性 ```javascript class Foo { } Foo.pro= 1 // 上面的写法为Foo类定义了一个静态属性。 // ES6规定class内部只有静态方法,没有静态属性,因此,只有上述写法可用。 ``` ### 三、class的继承 class引入目的就是让类定义起来更直观接单,通过extends关键字实现继承的写法也更便于理解。其中class A extends B 中A称为派生类,派生类是指继承自其它类的新类。 > super关键字:super代表的是父类构造函数,但是返回的是子类的实例。比如A是B的父类,那么super的功能相当于A.prototype.constructor.call(this)。super这个关键字既可以当做函数使用,也可以当做对象使用。 ##### 1.当做函数使用:super只能用在子类的构造函数中,用在其他地方会报错;当调用super时,它代表父类的构造函数 ( 这是规定 ) ,ES6还规定了子类的构造函数必须执行一次super函数; ```javascript class Superr { constructor () { console.log(new.target.name); } } class SonSuperr extends Superr { constructor () { super(); } } new Superr(); // Superr new SonSuperr(); // SonSuperr ``` super虽然代表父类,但是它返回的是子类的实例,也就是说super内部的this是指向子类的。 #### 2.当做对象使用:在普通方法中指向父类的原型对象,在静态方法中指向父类,由于 super 指向的是父类的原型对象,所以定义在父类实例上的方法或属性是无法通过 super 调用的: ```javascript class A { getA() { return ('a'); } } class B extends A { constructor () { super(); console.log(super. getA ()); // 'a' } } ``` ### 四、从源码解析class的原理 #### 1.class的基本用法如下: ```javascript class Person{ constructor(name, age){ this.name = name this.age = age } static type = 'being' sayName (){ return this.name } static intro(){ console.log("") } } class Men extends Person{ constructor(name, age){ super() this.gender = 'male' } } ``` #### 2.经过babel解析后,代码结构如下: ```javascript 'use strict'; var _createClass = function () {...}(); // 给类添加方法 function _possibleConstructorReturn(self, call) { ...} //实现super function _inherits(subClass, superClass) {...} // 实现继承 function _classCallCheck(instance, Constructor) {...} // 防止以函数的方式调用class var Person = function () { function Person(name, age) { _classCallCheck(this, Person); this.name = name; this.age = age; } _createClass(Person, [{ key: 'sayName', value: function sayName() { return this.name; } }], [{ key: 'intro', value: function intro() { console.log(""); } }]); return Person; }(); Person.type = 'being'; //静态变量 var Men = function (_Person) { _inherits(Men, _Person); function Men(name, age) { _classCallCheck(this, Men); var _this = _possibleConstructorReturn(this, (Men.__proto__ || Object.getPrototypeOf(Men)).call(this)); _this.gender = 'male'; return _this; } return Men; }(Person); var men = new Men(); ``` #### 3.具体解释一下开头的这四个函数: ##### (1) _classCallCheck函数, 检验构造函数的调用方式 ```javascript function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } ``` 该函数是用来检测类的调用方式。防止类的构造函数以普通函数的方式调用 ##### (2) _createClass函数,用来给类添加方法 ```javascript var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); //非静态函数 -> 原型 if (staticProps) defineProperties(Constructor, staticProps); return Constructor; // 静态函数 -> 构造函数 }; }(); ``` 该函数是通过Object.defineProperty给类添加方法,将静态方法添加到构造函数上,将非静态的方法添加到构造函数的原型对象上 ##### (3) _inherits函数实现继承 ```javascript function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, // 子类的原型的__proto__指向父类的原型 //给子类添加 constructor属性 subclass.prototype.constructor === subclass { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } } ); if (superClass) //子类__proto__ 指向父类 Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } ``` 该函数是实现了继承的方法 ##### (4) _possibleConstructorRetur函数实现super() ```javascript function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); //保证子类构造函数中 显式调用 super() } return call && (typeof call === "object" || typeof call === "function") ? call : self; } ``` 该函数是将子类的this指向父类 ### 参考文章 1.[ECMAScript® 2015 Language Specification](http://www.ecma-international.org/ecma-262/6.0/) 2.[详解ES6中的class](https://juejin.cn/post/6844904086089760775) 3.[ES6中的Class](https://juejin.cn/post/6844904051973292045) 4.[ES6之Class原理分析](https://blog.csdn.net/qq_41694291/article/details/103943481)
原创文章,需联系作者,授权转载
上一篇:揭秘京东城市时空数据引擎—JUST如何助力交通流量预测
下一篇:探索React异步解决方案之Redux-saga
相关文章
【技术干货】企业级扫描平台EOS关于JS扫描落地与实践!
开发也要防沉迷--IDEA插件教程
京东mPaaS平台之Android组件化系统私有化部署改造实践!
京东ZERO团队
文章数
39
阅读量
91754
作者其他文章
01
webpack打包组件配置(React版本)
这篇文章是以打包react插件的形式,介绍webpack的一些配置信息。如果写简单插件的话还是推荐使用rollup,但是可以用写插件的形式去学习一下webpack的一些东西。(适用于初中级webpack学者)
01
webpack核心概念与基本实现
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。**
01
Typescript合成Webpack中
TypeScript是JavaScript类型的超集,它可以编译成纯JavaScript,简称ts。相对于ES6,TypeScript最大的改善是增加了类型系统,国内外很多大型工程都用它,如AngularJs,白鹭引擎、Antd。
01
小程序加载svg图片
小程序的[组件](https://developers.weixin.qq.com/miniprogram/dev/component/)中是没有支持`SVG`标签的。 但是在前端小伙伴的实际开发中,UED经常提供SVG图片过来,如果不想用引入`iconfont`的话,那么妹子我将介绍个很好用的方法。
最新回复
丨
点赞排行
共0条评论
京东ZERO团队
文章数
39
阅读量
91754
作者其他文章
01
webpack打包组件配置(React版本)
01
webpack核心概念与基本实现
01
Typescript合成Webpack中
01
小程序加载svg图片
添加企业微信
获取1V1专业服务
扫码关注
京东云开发者公众号