ES6 中 class 和 extends 的es5实现
ES6 中 class 和 extends 实现原理
在学习中,我们通常会遇到这种场景,在阅读某段实现源码时我们往往能看懂大部分代码,但是却卡在其中的一两个点,导致无法继续阅读。 所以在这里我会先列出 class 和 extends 需要的预备知识。
属性描述符
Object.getOwnPropertyDescriptor()
方法获取元素的属性描述,
/*** 知识点:属性描述符* 从 ES5 开始,所有的属性都具备了属性描述符**/
var obj = {name: "jason"
};/*** getOwnPropertyDescriptor* 获取属性描述符*/
var des = Object.getOwnPropertyDescriptor(obj, "name");
console.log(des);/*** {* value: 'jason',* writable: true, // 可写* enumerable: true, // 可枚举* configurable: true // 可配置* }*/复制代码
Object.defineProperty()
定义对象上属性的一些特性
/*** Object.defineProperty* 该方法定义对象上属性的一些特性** 第一个参数,目标对象* 第二个参数,要添加或编辑的属性* 第三个参数,描述*/
var obj2 = {};
Object.defineProperty(obj2, "age", {value: 2,writable: true,configurable: true,enumerable: true
});
console.log(obj2.age); // 2复制代码
writable:
对象上的属性是否可以修改。兼容模式下编辑不可写元素会编辑失败,严格模式下会报错。
var obj3 = {};
Object.defineProperty(obj3, "age", {value: 2,writable: false,configurable: true,enumerable: true
});
obj3.age = 23;
console.log(obj3.age); // 2 不可修改复制代码
configurable:
对象上的属性是否可以配置
var obj4 = {};
Object.defineProperty(obj4, "age", {value: 22,writable: true,configurable: false, // 不可配置enumerable: true
});/*** 再次定义* 此时会报错*/
// Object.defineProperty(obj4, "age", {
// value: 22,
// writable: true,
// configurable: false,
// enumerable: true
// });delete obj4.age;
console.log(obj4.age); // 22 属性删除失败,应为属性不可配置复制代码
enumerable:
当 enumerable 为 false 之后,for...in 不会遍历到该对象
/*** enumerable* 当 enumerable 为 false 之后,for...in 不会遍历到该对象*/
var obj5 = {weight: "66kg"
};
Object.defineProperty(obj5, "height", {value: "176cm",writable: true,configurable: true,enumerable: false // 不可枚举
});
let keys = Object.keys(obj5);
console.log(keys); // [ 'weight' ] 属性 height 不可遍历复制代码
prototype,constructor,__proto__ 三者之间的关系
es6 中类的实现 和 es5 比较
es6 中类的实现
class Parent {constructor(name) {this.name = name;}/*** 静态方法,通过 Parent 调用*/static getMe() {console.log("this is super");}/*** 公共方法,在 prototype 上*/getName() {console.log(this.name);}
}复制代码
es5
实现方式
/*** 立即执行闭包* @param {*} Constructor 构造函数* @param {*} protoProps 原型属性* @param {*} staticProps 静态属性* @return {function}*/
var _createClass = (function() {/*** 为属性添加描述符* @param {object} target 目标对象* @param {Array} props 属性*/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);}}/*** @param {Object} Constructor* @param {array} protoProps 原型属性* @param {array} staticProps 静态属性*/return function(Constructor, protoProps, staticProps) {// 原型上属性, 添加到Constructor 的原型上if (protoProps) defineProperties(Constructor.prototype, protoProps);// 类上的属性, 添加到Constructor 类上if (staticProps) defineProperties(Constructor, staticProps);return Constructor;};
})();/*** 检测函数* es6 中 类不能直接调用* @param {*} instance 实例* @param {*} Constructor 构造函数*/
function _classCallCheck(instance, Constructor) {console.log(instance.__proto__);console.log(Constructor.prototype);// instance 是否是 Constructor 的实例console.log(instance.__proto__ === Constructor.prototype);if (!(instance instanceof Constructor)) {throw new TypeError("Cannot call a class as a function");}
}/*** 立即执行闭包* @return {function}*/
var Parent = (function() {function Parent(name) {// 验证是否是实例化类// es6不允许类直接调用,直接调用抛出异常_classCallCheck(this, Parent);this.name = name;}_createClass(Parent,[{key: "getName",value: function getName() {console.log(this.name);}}],[{key: "getMe",value: function getMe() {console.log("this is super");}}]);return Parent;
})();复制代码
es6 中继承的实现 和 es5 比较
es6
中继承的实现
class Child extends Parent {constructor(name, age) {super(name);this.age = age;}sayHello() {console.log(`hello my age is ${this.age}`);}
}复制代码
es5
继承关键字实现
/*** 继承* @param {*} subClass 子类* @param {*} superClass 父类*/
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);}/*** Object.create 接受两个参数* 指定原型创建对象* @param {*} 目标原型* @param {*} 添加属性*/subClass.prototype = Object.create(superClass && superClass.prototype, {constructor: {value: subClass, // subClass.prototype.constructor 指向 subClassenumerable: false, // constructor 不可枚举writable: true,configurable: true}});/*** Object.setPrototypeOf 方法* 设置子类的 __proto__ 属性指向父类* @param {*} 子类* @param {*} 父类*/if (superClass) {// 设置子类的__proto__ 让 Child 能访问父类静态属性Object.setPrototypeOf? Object.setPrototypeOf(subClass, superClass): (subClass.__proto__ = superClass);}
}复制代码
es5
中继承的实现
/*** 调用父类的 Constructor 构造函数*/
function _possibleConstructorReturn(self, call) {if (!self) {throw new ReferenceError("this hasn't been initialised - super() hasn't been called");}return call && (typeof call === "object" || typeof call === "function")? call: self;
}/*** @param {*} _Parent 传入父类*/
var Child = (function(_Parent) {_inherits(Child, _Parent);function Child(name, age) {_classCallCheck(this, Child);/*** 调用父类的 Constructor 构造函数*/var _this = _possibleConstructorReturn(this,(Child.__proto__ || Object.getPrototypeOf(Child)).call(this, name) // 调用父类Constructor);_this.age = age;return _this;}_createClass(Child, [{key: "sayHello",value: function sayHello() {console.log("hello my age is " + this.age);}}]);return Child;
})(Parent);复制代码
完结
以上就是 es6 class 和 extends 的 es5 实现方式,以上代码有一些隐藏细节还需要自学,以下是用到的知识点
- 属性描述符
- Object.create 引用原型链需要指定 Constructor 属性
- new 关键字的实现方式 其中需要设置 __proto__ 属性
- Object.setPrototypeOf 实现原理 让子类的__proto__ = 父类
- instanceof 判断 子类的__proto__ === 父类
- 调用子类的 Constructor 也会调用父类的 Constructor
- 设置子类的 __proto__ = 父类,让子类可以调用父类静态方法
ES6 中 class 和 extends 的es5实现相关推荐
- ES5和ES6中对于继承的实现方法
在ES5继承的实现非常有趣的,由于没有传统面向对象类的概念,Javascript利用原型链的特性来实现继承,这其中有很多的属性指向和需要注意的地方. 原型链的特点和实现已经在之前的一篇整理说过了,就是 ...
- es6中的类及es5类的实现
目录 类的特点 类的特点 1.类只能通过new得到 在es6中类的使用只能是通过new,如果你将它作为一个函数执行,将会报错. //es6的写法 class Child {constructor() ...
- ES5与ES6中如何实现继承
ES5中实现继承 // 使用类或不使用类继承 // 继承 (2个类连起来) function Animal (lengthNumber) {this.lengthNumber = legsNumber ...
- ES6中的class是如何实现的?(附Babel编译的ES5代码详解)
序言 这篇文章主要讲解面试某大厂遇到的一个问题 - ES6中的class语法的实现? ECMAScript 6 实现了class,class是一个语法糖,使得js的编码更清晰.更人性化.风格更接近面向 ...
- ES5和ES6中的变量声明提升
ES5和ES6中的变量声明提升 Example1: a=2; var a; console.log( a ); //结果为2 Example2: console.log( a ); //结果是unde ...
- es5与es6中如何处理不确定参数?以及es6中rest parameter的强大之处
本人学习过程中编写,定有不足之处,如果有错误,请您积极指正:如果有帮助,请不要吝啬您的赞美(点赞),欢迎各位大佬点赞评论. es5中处理不确定参数(arguments) function sum(){ ...
- ES5合并数组---ES6中合并数组
合同数组的方法, 其中,ES6中扩展运算符提供了数组合并的新写法. formatEs6ConcatArr () {let arr1 = ['a', 'b']let arr2 = ['c', 'c']l ...
- ES5和ES6中的this指向
ES5和ES6中的this指向 ES5: 1.在普通函数中,this指向的是函数调用者,默认情况下,this指向的是window 2.在严格模式下,如果没有直接调用者,在函数中,this的值为unde ...
- JavaScript-----静态成员在ES5和ES6中的实现
在学习静态成员在ES5和ES6中的实现之前我们先来了解一下静态成员的定义. 静态成员 :类的所有对象共享的成员(类的成员变量(属性)和成员方法) 看完这个定义我相信大家还是不太了解静态成员是什么意思 ...
最新文章
- linux下yum错误:[Errno 14] problem making ssl connection Trying other mirror.
- linux查看文件及文件夹的大小
- Maven——常用命令详解
- 指针、引用以及const限定符、constexpr限定符
- Asp.NetCore之组件写法
- 朋友圈设置成昨天发的_如何让你的朋友圈骚到脱颖而出?
- js获取DIV的位置坐标的三种方法!
- pytorch 实现RBF网络
- 操作系统 读者-写者问题
- 如何在Cesium中加载谷歌离线影像数据
- ubuntu下配置vscode和opencv4要点记录
- OPCClient远程连接OPC服务器配置手册
- 大规模定制家具实施ERP的必要性
- JavaScript jQuery修改样式
- Jenkins 添加侧边栏按钮链接 Sidebar Link插件
- 第一段代码 打开了新世界的大门
- Linux,常用shell命令【删除文件或目录】
- python小游戏-移动木板
- DOS远程桌面连接命令[佚名]
- 饥荒联机版Mod开发——modmain(五)