12.ES6类的使用和转ES5源码阅读
ES6也称为:ES2015,ECMAScript2015
ES12 对应:ES2021
//类的声明
class Person { } //是语法糖,对应:function Person() { }
//类的表达式
//var Animal = class { }
// 研究一下类的特点
console.log(Person.prototype)
console.log(Person.prototype.__proto__)
console.log(Person.prototype.constructor) //[class Person]
console.log(typeof Person) //function
var p = new Person()
console.log(p.__proto__ === Person.prototype) //true
00:43:00
//类的声明
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
this._address = "广州市"
}
//普通的实例方法
//创建出来的对象进行访问
// var p = new Person()
// p.eating ()|
eating() {
console.log(this.name + " eating~")
}
running() {
console.log(this.name + " running~")
}
//类的访问器方法
get address() {
return this._address
}
set address(newAddress) {
this._address = newAddress
}
//类的静态方法(类方法) 【通过类名访问的方法】
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 p1 = new Person("why", 18)
var p2 = new Person("kobe", 30)
var p = new Person("why", 18)
p.eating()
p.running()
console.log(Object.getOwnPropertyDescriptors(Person.prototype))
var pl = Person.randomPerson()
console.log(pl)
01:12:00
//ES6 继承的实现
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + " eating~")
}
running() {
console.log(this.name + " running~")
}
static staticMethod() {
console.log("PersonStaticMethod")
}
}
// Student称之为子类(派生类)
class Student extends Person {
constructor(name, age, sno){
//没用super时报错 【ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor】
super(name,age)
this.sno = sno
}
studying() {
super.eating()
console.log(this .name + " studying~")
}
// 类对父类的方法的重写
running() {
console.log("student " + this.name +"running")
}
//重写静态方法
static staticMethod() {
//复用父类中的处理逻辑
super.personMethod()
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.studying()
Student.staticMethod()
我们会发现在上面的代码中我使用了一个super关键字,这个super关键字有不同的使用方式:
· 注意:在子(派生)类的构造函数中使用this或者返回默认对象之前,必须先通过super调用父类的构造函数
· super的使用位置有三个:子类的构造函数、实例方法、静态方法;
静态方法,比如:
Promise.all/Promise.resolve/reject 这些都是静态方法
console.log(Object.getOwnPropertyDescriptors(Person))
上面打印出来,静态方法是在函数上面的,不在函数的原型上面。
01:48:00
JS中比较新的语法,到底能不能写!【可以的】
脚手架中通过(babel)工具就能转成相应适配。
vue cli
webpack环境 (babel)
babel是什么? 将新JS、TS代码 转成-> 较低版本浏览器可以识别的代码
https://babeljs.io/
里面“TARGETS”设置:defaults, not ie 11, not ie_mob 11
即:默认,不支持IE11,不支持IE11移动端
比如设置为:defaults, not ie 10, not ie_mob 11 则 babel为下面这个:
class Person { }
//转成下面的
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)){
throw new TypeError("Cannot call a class as a function");
}
}
var Person = function Person() {
_classCallCheck(this, Person);
}
new Person()
_classCallCheck作用是限制你直接调用 Person()【报错】
把下面【类无继承代码】也用 babel转一下:
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
eating() {
console.log(this.name + " eating~")
}
}
再来看看babel转成的代码:
var Person = /*#__PURE__*/ (function (){
function Person(name,age) {
_classCallCheck(this, Person);
this.name = name;
this.age = age;
}
_createClass(Person, [
{
key: "eating",
value: function eating() {
console.log(this.name + " eating~");
}
}
]);
return Person;
})();
这边用到“立即执行函数”,其实会在整个作用域中直接执行的。简化一下去掉(头尾),只保留中间代码(……):
var Person = /*#__PURE__*/ (function (){
…………
return Person;
})();
那为什么生成的代码要用到“立即执行函数”呢?原因有两个:
1、担心在立即执行函数里面生成的东西(变量|函数等),放到了全局里面了,有可能会跟全局里面的某一段代码是有冲突的。
放到“立即执行函数”里面,可以避免出现这种情况。
2、“立即执行函数”前面有弄了一个标记的 /*#__PURE__*/ ,它相当于一种魔法注释,它后面在代码压缩的时候:
// /*#__PURE__*/ 纯函数
// jsx -> babel -> React.createElement 【也是标记纯函数的】
// webpack 压缩 tree-shaking(因为纯函数在进行压缩时可用“tree-shaking”技术的)
即最终生成的代码从来都没有用到的,“摇树”一下,就可以把没用到的代码删掉。
继续看生成的代码:
function _createClass(Constructor, protoProps, staticProps) {
if (protoProps) _defineProperties(Constructor.prototype, protoProps);
if (staticProps) _defineProperties(Constructor, staticProps);
return Constructor;
}
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);
}
}
上上面的两段代码相当于是对下面进行【封装】:
Person.prototype.eating = function() {
console.log(this.name + " eating~")
}
02:16:10
把下面【类有继承代码】也用 babel转一下:
class Person {
constructor(name, age) {
this.name = name
this.age = age
}
running() {
console.log(this.name + " running~")
}
}
class Student extends Person {
constructor(name, age, sno){
super(name, age)
this.sno = sno
}
studying() {
console.log(this.name + " studying~")
}
}
// babel转换后的代码
"use strict";
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);
// 因为有限制 Person不能独立函数调用
var _super =_createSuper(Student);
function Student(name, age, sno) {
var _this;
_classCallCheck(this, Student);
// debugger; //可以试着加入调试
// 创建出来的对象 {name: …, age: …}
_this = _super.call(this, name, age);
_this.sno = sno;
return _this;
}
_createClass(Student, [
{
key: "studying",
value: function studying() {
console.log(this.name + " studying~");
}
}
]);
return Student;
})(Person);
var Student = /*#__PURE__*/ (function (_Person){
})(Person);
function _inherits(subClass, superClass) {
if (typeof superclass !== "function" && superClass !== null) {
throw new TypeError("Super expression must either be null or a function");
}
// 这边用到逻辑与 superClass && 即:superClass 有值的情况下,才用 superClass.prototype
// Object.create会创建一个【新的对象__proto__】指向 父类的原型对象【superClass.prototype】
// 然后,把新的对象赋值给【subClass.prototype】
// 即是:Student.prototype = 新的对象.__proto__ = Person.prototype
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: { value: subclass, writable: true, configurable: true }
});
// 即是:Student.__proto__ = Person 【目的:静态方法的继承】
// 静态方法:Student.__proto__ = Function.prototype 而 Function.prototype 中没有静态方法
// 所以上面:Student.__proto__ = Person 因为 Person 中是有静态方法的,因为 Student中找不到就会去 Person中找
if (superClass) _setPrototypeOf(subClass, superClass);
}
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 = _getPrototype0f(Derived),
result;
if (hasNativeReflectConstruct) {
var NewTarget = _getPrototype0f(this).constructor;
result = Reflect.construct(Super, arguments, NewTarget);
} else {
result = Super.apply(this, arguments);
}
return _possibleConstructorReturn(this, result);
};
}
读源码时,这边我们先如下调试:
var stu = new Student()
具体说明:
// Super: Person
// arguments: ["why",·18]
// NewTarget: Student
Reflect.construct(Super, arguments, NewTarget);
// 会通过Super 创建出来一个实例,但是这个实例的原型constructor指向的是NewTarget 对应翻译是
// 会通过Person创建出来一个实例,但是这个实例的原型constructor指向的Person
02:53:00
阅读源码大家遇到的最大的问题:
1.一定不要浮躁
2.看到后面忘记前面的东西
· VSCode插件中 Bookmarks的打标签的工具: command(ctrl) + alt + k
· 读一个函数的时候忘记传进来是什么?
3.读完一个函数还是不知道它要干嘛【多积累】
4.debugger 打断点的方式
笔记-ES6类的使用和转ES5源码阅读&spm=1001.2101.3001.5002&articleId=147159656&d=1&t=3&u=2787d59e22dc47018566d912eb60fdd1)
465

被折叠的 条评论
为什么被折叠?



