自从有了webpack之后,我们这些jscoder似乎得到了前所未有的解放,箭头函数,对象解构,let,const关键字,以及class、extends等等关键字使用得不亦乐乎,反正,webpack会帮我们把这些es6代码转换成浏览器能够识别的es5代码,那么,我们有多少人真正的看过,babel转换之后的代码呢?今天,我就来看一下,当我们使用关键词class的时候,babel到底做了什么?
我推荐打开网址:https://babeljs.io/repl,这里我们左边写es6代码,马上右边就能转译出es5代码,然后,我在左边输入了如下代码:
class A {
constructor(name) {
this.name = name
}
getName() {
return this.name
}
}
这是一个最简单的类,一个属性,一个方法。
这时候,右边框已经给我转译出了浏览器可识别的es5代码了,格式化之后是这样的:
'use strict';
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;
};
}();
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
var A = function () {
function A(name) {
_classCallCheck(this, A);
this.name = name;
}
_createClass(A, [{
key: 'getName',
value: function getName() {
return this.name;
}
}]);
return A;
}();
好,现在来分析一下这段代码。
// 自执行函数
var A = function () {
function A(name) {
// 这个函数的目的其实是防止这个构造函数被当做普通函数执行
_classCallCheck(this, A);
this.name = name;
}
// 对函数A执行_createClass方法,其实就是给A的原型上绑定方法
_createClass(A, [{
key: 'getName', //方法名
value: function getName() { //函数体
return this.name;
}
}]);
return A;
}();
这段代码,变量A是一个自执行函数的返回值,该自执行函数的返回值其实就是我们熟悉的构造函数,所以,es6里面的类其实就是一个构造函数。
function _classCallCheck(instance, Constructor) {
if (!(instance instanceof Constructor)) {
throw new TypeError('Cannot call a class as a function');
}
}
这个函数特别简单,当执行函数A的时候,不允许this不是A的子类实例,比如直接这样调用A(),但是在A的子类B中可以这样调用:A.apply(this, arguments)。
该函数的目的是防止构造函数被当做普通函数执行。
//该函数也是一个自执行的函数,其返回值是一个函数
var _createClass = function () {
// 把props数组上每一个对象,通过Object.defineProperty方法,都定义到目标对象target上去
function defineProperties(target, props) {
for (var i = 0; i < props.length; i++) {
//这里要确保props[i]是一个对象,并且有key和value两个键
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) {
// 如果传入了原型属性数组,就把属性全部定义到Constructor的原型上去
if (protoProps) defineProperties(Constructor.prototype, protoProps);
// 如果传入了静态属性数组,就把属性全部定义到Constructor对象自身上去
if (staticProps) defineProperties(Constructor, staticProps);
return Constructor;
};
}();
其实_createClass函数做的事情,就是把几个方法拷贝到构造函数A的原型上去。
我在https://babeljs.io/repl 左侧输入框上加了下面这行代码:
class B extends A {}
这时候,右侧多出了以下几行代码:
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;
}
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, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
var B = function (_A) {
_inherits(B, _A);
function B() {
_classCallCheck(this, B);
//这里的重点是第二个参数:(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments);
//这里其实是将子类的实例对象,调用了父类的构造函数方法,这样父类的属性就都可以拷贝到子类上来
return _possibleConstructorReturn(this, (B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments));
}
return B;
}(A);
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);
}
//把子类的原型指向父类的原型创建出来的对象(注意不是直接指向父类原型),并且修正constructor属性为子类自己
subClass.prototype = Object.create(superClass && superClass.prototype, {
constructor: {
value: subClass,
enumerable: false,
writable: true,
configurable: true
}
});
// 这一步操作,其实是想把superClass放到subClass下,相当于subClass.super = superClass,这样后面的代码中,subClass里面能方便的引用到superClass函数
if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;
}
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;
}
如果call不是对象或者函数,即该调用:(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值既不是对象,也不是函数,那么,就直接返回当前的self,而self其实就是子类B里面的实例指针this。正常情况,(B.__proto__ || Object.getPrototypeOf(B)).apply(this, arguments)的返回值就是一个对象,其实也就是对象。
原文:https://segmentfault.com/a/1190000015125847
Promise是一个构造函数,接受一个参数(Function),并且该参数接受两个参数resolve和reject(分别表示异步操作执行成功后的回调函数、执行失败后的回调函数)
利用Promise是解决JS异步执行时候回调函数嵌套回调函数的问题, 更简洁地控制函数执行流程;通过new实例化Promise, 构造函数需要两个参数
顾名思义,用于对象或数组之前的展开操作符(…),将一个结构展开为列表。这种写法够优雅,够简洁吧?如果不用展开操作符
export 在接口名字与模块内部的变量之间建立了一一对应的关系,export输出的接口; export的写法,除了像上面这样,还有另外一种。export命令除了输出变量,还可以输出函数或类(class)。
在阅读 《ECMAScript 6 入门》的时候,零散的看到有私有变量的实现。旨在加深 ES6 部分知识点的理解,重点讲解块级作用域、标签模板、箭头函数、Symbol、Set、Map 以及 Promise 的模拟实现、模块加载方案、异步处理等内容
const是用来定义常量的,而且定义的时候必须初始化,且定义后不可以修改。const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。
require 和 import 区别:遵循的模块化规范不一样,出现的时间不同。Require是CommonJS的语法,CommonJS的模块是对象,输入时必须查找对象属性。
如果模块中使用 export default {},只能通过 import 对象名称 from 模块路径 ,不能通过 import {对象名称} from 模块路径。如果使用 import {对象名称} from 模块路径 导出具体某个对象或者方法名称
Reflect是ES6为操作对象而提供的新API,而这个API设计的目的只要有:将Object对象的一些属于语言内部的方法放到Reflect对象上,从Reflect上能拿到语言内部的方法。如:Object.defineProperty,修改某些object方法返回的结果。让Object的操作都变成函数行为。
本文将研究 ES6 的 for ... of 循环。在过去,有两种方法可以遍历 javascript。首先是经典的 for i 循环,它使你可以遍历数组或可索引的且有 length 属性的任何对象。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!