第十节:ES6类的使用详解(声明、构造、方法、继承、多态等)
一. class类基础
1. 类的声明
使用关键字class声明
// 类的声明 class Person { } // 类的表达式 // var Animal = class { // } // 研究一下类的特性 console.log(Person.prototype) console.log(Person.prototype.__proto__) console.log(Person.prototype.constructor) console.log(typeof Person) // function var p = new Person() console.log(p.__proto__ === Person.prototype) // true
2. 类的构造方法
使用 constructor 关键字
// 类的声明 class Person { // 类的构造方法 // 注意: 一个类只能有一个构造函数 // 1.在内存中创建一个对象 moni = {} // 2.将类的原型prototype赋值给创建出来的对象 moni.__proto__ = Person.prototype // 3.将对象赋值给函数的this: new绑定 this = moni // 4.执行函数体中的代码 // 5.自动返回创建出来的对象 constructor(name, age) { this.name = name this.age = age } } var p1 = new Person("why", 18) var p2 = new Person("kobe", 30) console.log(p1, p2)
3. 方法定义
这里方法包括:普通的实例方法、类的访问器方法、类的静态方法。
代码分享:
var names = ["abc", "cba", "nba"] class Person { constructor(name, age) { this.name = name this.age = age this._address = "广州市" } // 普通的实例方法 // 创建出来的对象进行访问 // var p = new Person() // p.eating() eating() { console.log(this.name + " eating~") } running() { console.log(this.name + " running~") } // 类的访问器方法 get address() { console.log("拦截访问操作") return this._address } set address(newAddress) { console.log("拦截设置操作") this._address = newAddress } // 类的静态方法(类方法) // Person.createPerson() static randomPerson() { var nameIndex = Math.floor(Math.random() * names.length) var name = names[nameIndex] var age = Math.floor(Math.random() * 100) return new Person(name, age) } } var p = new Person("why", 18) p.eating() p.running() console.log(p.address) p.address = "北京市" console.log(p.address) // console.log(Object.getOwnPropertyDescriptors(Person.prototype)) for (var i = 0; i < 50; i++) { console.log(Person.randomPerson()) }
4. 类的继承
子类通过 extends 关键字实现继承,在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数!
super的使用位置有三个:子类的构造函数、实例方法、静态方法;
代码分享:
class Person { constructor(name, age) { this.name = name this.age = age } running() { console.log(this.name + " running~") } eating() { console.log(this.name + " eating~") } personMethod() { console.log("处理逻辑1") console.log("处理逻辑2") console.log("处理逻辑3") } static staticMethod() { console.log("PersonStaticMethod") } } // Student称之为子类(派生类) class Student extends Person { // JS引擎在解析子类的时候就有要求, 如果我们有实现继承 // 那么子类的构造方法中, 在使用this之前 constructor(name, age, sno) { super(name, age) this.sno = sno } studying() { console.log(this.name + " studying~") } // 类对父类的方法的重写 running() { console.log("student " + this.name + " running") } // 重写personMethod方法 personMethod() { // 复用父类中的处理逻辑 super.personMethod() console.log("处理逻辑4") console.log("处理逻辑5") console.log("处理逻辑6") } // 重写静态方法 static staticMethod() { super.staticMethod() console.log("StudentStaticMethod") } } var stu = new Student("why", 18, 111) console.log(stu) // console.log(Object.getOwnPropertyDescriptors(stu.__proto__)) // console.log(Object.getOwnPropertyDescriptors(stu.__proto__.__proto__)) stu.eating() stu.running() stu.personMethod() Student.staticMethod() console.log(Object.getOwnPropertyDescriptors(Person))
二. class类高级
1. ES6转ES5代码
class类的转换
class Person { constructor(name, age) { this.name = name this.age = age } eating() { console.log(this.name + " eating~") } } // babel转换 "use strict"; function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } // /*#__PURE__*/ 纯函数 // webpack 压缩 tree-shaking // 这个函数没副作用 var Person = /*#__PURE__*/ (function () { function Person(name, age) { this.name = name; this.age = age; } _createClass(Person, [ { key: "eating", value: function eating() { console.log(this.name + " eating~"); } } ]); return Person; })();
继承的转换
// class Person { // constructor(name, age) { // this.name = name // this.age = age // } // running() { // console.log(this.name + " running~") // } // static staticMethod() { // } // } // class Student extends Person { // constructor(name, age, sno) { // super(name, age) // this.sno = sno // } // studying() { // console.log(this.name + " studying~") // } // } // babel转换后的代码 "use strict"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); // 目的静态方法的继承 // Student.__proto__ = Person if (superClass) _setPrototypeOf(subClass, superClass); } // o: Student // p: Person // 静态方法的继承 function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError( "Derived constructors may only return object or undefined" ); } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError( "this hasn't been initialised - super() hasn't been called" ); } return self; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call( Reflect.construct(Boolean, [], function () {}) ); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a 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); } } function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; } var Person = /*#__PURE__*/ (function () { function Person(name, age) { _classCallCheck(this, Person); this.name = name; this.age = age; } _createClass(Person, [ { key: "running", value: function running() { console.log(this.name + " running~"); } } ]); return Person; })(); var Student = /*#__PURE__*/ (function (_Person) { // 实现之前的寄生式继承的方法(静态方法的继承) _inherits(Student, _Person); var _super = _createSuper(Student); function Student(name, age, sno) { var _this; _classCallCheck(this, Student); // Person不能被当成一个函数去调用 // Person.call(this, name, age) debugger; // 创建出来的对象 {name: , age: } _this = _super.call(this, name, age); _this.sno = sno; // {name: , age:, sno: } return _this; } _createClass(Student, [ { key: "studying", value: function studying() { console.log(this.name + " studying~"); } } ]); return Student; })(Person); var stu = new Student() // Super: Person // arguments: ["why", 18] // NewTarget: Student // 会通过Super创建出来一个实例, 但是这个实例的原型constructor指向的是NewTarget // 会通过Person创建出来一个实例, 但是这个实例的原型constructor指向的Person Reflect.construct(Super, arguments, NewTarget);
2. 内置类
代码分享:
class HYArray extends Array { firstItem() { return this[0] } lastItem() { return this[this.length-1] } } var arr = new HYArray(1, 2, 3) console.log(arr.firstItem()) console.log(arr.lastItem())
3. JS中实现混入效果
代码分享:
class Person { } function mixinRunner(BaseClass) { class NewClass extends BaseClass { running() { console.log("running~") } } return NewClass } function mixinEater(BaseClass) { return class extends BaseClass { eating() { console.log("eating~") } } } // 在JS中类只能有一个父类: 单继承 class Student extends Person { } var NewStudent = mixinEater(mixinRunner(Student)) var ns = new NewStudent() ns.running() ns.eating()
4. JS中实现面向对象
(1). 传统的面向对象多态是有三个前提:
A 必须有继承(是多态的前提)
B 必须有重写(子类重写父类的方法)
C 必须有父类引用指向子类对象
代码分享:
// Shape形状 class Shape { getArea() {} } class Rectangle extends Shape { getArea() { return 100 } } class Circle extends Shape { getArea() { return 200 } } var r = new Rectangle() var c = new Circle() // 多态: 当对不同的数据类型执行同一个操作时, 如果表现出来的行为(形态)不一样, 那么就是多态的体现. function calcArea(shape: Shape) { console.log(shape.getArea()) } calcArea(r) calcArea(c) export {}
(2). 多态
当对不同的数据类型执行同一个操作时, 如果表现出来的行为(形态)不一样, 那么就是多态的体现.
代码分享:
function calcArea(foo) { console.log(foo.getArea()) } var obj1 = { name: "why", getArea: function() { return 1000 } } class Person { getArea() { return 100 } } var p = new Person() calcArea(obj1) calcArea(p) // 也是多态的体现 function sum(m, n) { return m + n } sum(20, 30) sum("abc", "cba")
!
- 作 者 : Yaopengfei(姚鹏飞)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 声 明1 : 如有错误,欢迎讨论,请勿谩骂^_^。
- 声 明2 : 原创博客请在转载时保留原文链接或在文章开头加上本人博客地址,否则保留追究法律责任的权利。