日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

 

不吹不捧,5和6做個(gè)對(duì)比,ES6及以上版本是由多個(gè)功能組成的,這是一個(gè)多維度的比較,不能簡(jiǎn)單抽象成6比5好。

為了兼容老的瀏覽器,尤其是IE系列,使用ES6以上規(guī)范的前端代碼往往使用Babel等轉(zhuǎn)碼工具轉(zhuǎn)碼成ES5的代碼。

距離發(fā)布ES6的2015年已經(jīng)過(guò)去了7年了,現(xiàn)在瀏覽器對(duì)于ES6的兼容性如何呢?

我們來(lái)看下CanIUse的數(shù)據(jù):

 

可以看到,有98.14%的瀏覽器支持ES6. 沒(méi)有超過(guò)99%的原因是因?yàn)?015年發(fā)布的Opera Mini還有1.08%的使用率。

針對(duì)手機(jī)端,2016年以后發(fā)布的Safari on IOS和Chrome等全部都支持ES6.
Safari on iOS 7-9.3目前的用戶占比0.15%.

Android從5版本開始WebView已經(jīng)全線支持ES6.

從數(shù)據(jù)上看起來(lái),因?yàn)閿?shù)量很少的老設(shè)備導(dǎo)致近99%以上的設(shè)備能力沒(méi)有應(yīng)用起來(lái),似乎并沒(méi)有說(shuō)服力。

另外,很多應(yīng)用針對(duì)低端機(jī)有特殊的處理,中高端機(jī)一定是近期的老設(shè)備。至少針對(duì)中高端機(jī),轉(zhuǎn)碼的兼容性必要性基本上是可以忽略的。

不過(guò),ES6及以上版本是由多個(gè)功能組成的,不能簡(jiǎn)單抽象成6比5好。
我們將主要的功能轉(zhuǎn)碼和不轉(zhuǎn)碼做一個(gè)對(duì)比。

不轉(zhuǎn)碼效果更好

const

const是要帶常量檢查的。我們來(lái)個(gè)例子:

let f1 = () => {
  const a = 0;
  a = 2;
};
f1();

轉(zhuǎn)碼之后,Babel幫我們生成了一個(gè)_readOnlyError函數(shù)。

function _readOnlyError(name) { throw new TypeError(""" + name + "" is read-only"); }

var f1 = function f1() {
  var a = 0;
  2, _readOnlyError("a");
};
f1();

這個(gè)不用看字節(jié)碼了,看源碼就知道是哪個(gè)更好了。

數(shù)組拷貝

ES6之后,我們做數(shù)組拷貝使用擴(kuò)展運(yùn)算符"...".

const a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  let a2 = [...a1];

Babel做的轉(zhuǎn)碼也不含糊,一個(gè)concat函數(shù)搞定:

var a1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
  var a2 = [].concat(a1);

但是,從字節(jié)碼角度來(lái)看,就不一樣了。因?yàn)関8提供了CreateArrayFromIterable指令。

所以,轉(zhuǎn)碼之前,9個(gè)字節(jié)的指令就搞定了:

Bytecode length: 9Parameter count 1Register count 2Frame size 16OSR nesting level: 0Bytecode Age: 0         0x3c140829374e @    0 : 79 00 00 25       CreateArrayLiteral [0], [0], #37         0x3c1408293752 @    4 : c4                Star0          0x3c1408293753 @    5 : 7a                CreateArrayFromIterable          0x3c1408293754 @    6 : c3                Star1          0x3c1408293755 @    7 : 0e                LdaUndefined          0x3c1408293756 @    8 : a9                Return Constant pool (size = 1)0x3c1408293721: [FixedArray] in OldSpace - map: 0x3c1408002205 <Map> - length: 1           0: 0x3c1408293715 <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x3c14082936e5 <FixedArray[10]>>

轉(zhuǎn)碼之后就是函數(shù)調(diào)用了,還有生成一個(gè)空數(shù)組,一共需要21個(gè)字節(jié):

0x3c1408293696 @    0 : 79 00 00 25       CreateArrayLiteral [0], [0], #37
         0x3c140829369a @    4 : c4                Star0 
         0x3c140829369b @    5 : 7b 01             CreateEmptyArrayLiteral [1]
         0x3c140829369d @    7 : c1                Star3 
         0x3c140829369e @    8 : 2d f7 01 02       LdaNamedProperty r3, [1], [2]
         0x3c14082936a2 @   12 : c2                Star2 
         0x3c14082936a3 @   13 : 5e f8 f7 fa 04    CallProperty1 r2, r3, r0, [4]
         0x3c14082936a8 @   18 : c3                Star1 
         0x3c14082936a9 @   19 : 0e                LdaUndefined 
         0x3c14082936aa @   20 : a9                Return 
Constant pool (size = 2)
0x3c1408293665: [FixedArray] in OldSpace
 - map: 0x3c1408002205 <Map>
 - length: 2
           0: 0x3c1408293659 <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x3c1408293629 <FixedArray[10]>>
           1: 0x3c1408202e9d <String[6]: #concat>

String.raw

對(duì)于String.raw,轉(zhuǎn)碼也是會(huì)多生成函數(shù)的。

比如轉(zhuǎn)碼前是這樣:

let f1 = () => {
  String.raw`n`;
};

f1();

轉(zhuǎn)碼之后,Babel幫我們生成了一個(gè)_taggedTemplateLiteral函數(shù):

var _templateObject;

function _taggedTemplateLiteral(strings, raw) { if (!raw) { raw = strings.slice(0); } return Object.freeze(Object.defineProperties(strings, { raw: { value: Object.freeze(raw) } })); }

var f1 = function f1() {
    String.raw(_templateObject || (_templateObject = _taggedTemplateLiteral(["n"])));
};

f1();

Symbol

Symbol是ES6新增的數(shù)據(jù)類型。

在ES6里,我們要判斷其類型,直接使用typeof運(yùn)算符就好。

let f2 = () => {
  let s1 = Symbol();
  return typeof s1;
};

這可難為Babel了,都得引入一個(gè)庫(kù)才能解決:

function _typeof(obj) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && "function" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }, _typeof(obj); }

var f1 = function f1() {
  var s1 = Symbol();
  return _typeof(s1);
};

rest參數(shù)

為了支持rest參數(shù),v8提供了CreateRestParameter指令。不過(guò),原有的arguments也是有CreateMAppedArguments指令支持的。
二者算是打平。

不過(guò),從源代碼的角度來(lái)看,不轉(zhuǎn)碼的會(huì)短一些:

let f1 = (...values) => {
    let sum = 0;
    for (let v of values) {
        sum += v;
    }
    return sum;
};
f1(1, 4, 9);

轉(zhuǎn)碼之后如下:

var f1 = function f1() {
    var sum = 0;

    for (var _len = arguments.length, values = new Array(_len), _key = 0; _key < _len; _key++) {
        values[_key] = arguments[_key];
    }

    for (var _i = 0, _values = values; _i < _values.length; _i++) {
        var v = _values[_i];
        sum += v;
    }

    return sum;
};

可選catch參數(shù)

這是ES2019的特性,可以省略catch中的錯(cuò)誤類型。在2018年上半年即被safari所支持。

let f3 = f2 => {
  try {
    f2();
  } catch {
    console.error("Error");
  }
};

轉(zhuǎn)碼之后,Babel會(huì)給我們生成一個(gè)未使用的error變量_unused:

var f1 = function f1(f2) {
    try {
        f2();
    } catch (_unused) {
        console.error("Error");
    }
};

帶有error變量的情況下,v8通過(guò)CreateCatchContext為我們生成CatchContext,并且為catch塊生成了一個(gè)CATCH_SCOPE:

         0x1937082936b6 @    0 : 19 ff fa          Mov <context>, r0
         0x1937082936b9 @    3 : 61 03 00          CallUndefinedReceiver0 a0, [0]
         0x1937082936bc @    6 : 8a 20             Jump [32] (0x1937082936dc @ 38)
         0x1937082936be @    8 : c3                Star1 
         0x1937082936bf @    9 : 82 f9 00          CreateCatchContext r1, [0]
         0x1937082936c2 @   12 : c4                Star0 
         0x1937082936c3 @   13 : 10                LdaTheHole 
         0x1937082936c4 @   14 : a6                SetPendingMessage 
         0x1937082936c5 @   15 : 0b fa             Ldar r0
         0x1937082936c7 @   17 : 1a f9             PushContext r1
         0x1937082936c9 @   19 : 21 01 02          LdaGlobal [1], [2]
         0x1937082936cc @   22 : c1                Star3 
         0x1937082936cd @   23 : 2d f7 02 04       LdaNamedProperty r3, [2], [4]
         0x1937082936d1 @   27 : c2                Star2 
         0x1937082936d2 @   28 : 13 03             LdaConstant [3]
         0x1937082936d4 @   30 : c0                Star4 
         0x1937082936d5 @   31 : 5e f8 f7 f6 06    CallProperty1 r2, r3, r4, [6]
         0x1937082936da @   36 : 1b f9             PopContext r1
         0x1937082936dc @   38 : 0e                LdaUndefined 
         0x1937082936dd @   39 : a9                Return 
Constant pool (size = 4)
0x19370829367d: [FixedArray] in OldSpace
 - map: 0x193708002205 <Map>
 - length: 4
           0: 0x193708293649 <ScopeInfo CATCH_SCOPE>
           1: 0x193708202741 <String[7]: #console>
           2: 0x193708202769 <String[5]: #error>
           3: 0x19370800455d <String[5]: #Error>

而對(duì)于可選catch參數(shù)的情況下,直接不生成CatchContext:

         0x19370829376a @    0 : 19 ff fa          Mov <context>, r0
         0x19370829376d @    3 : 61 03 00          CallUndefinedReceiver0 a0, [0]
         0x193708293770 @    6 : 8a 15             Jump [21] (0x193708293785 @ 27)
         0x193708293772 @    8 : 10                LdaTheHole 
         0x193708293773 @    9 : a6                SetPendingMessage 
         0x193708293774 @   10 : 21 00 02          LdaGlobal [0], [2]
         0x193708293777 @   13 : c2                Star2 
         0x193708293778 @   14 : 2d f8 01 04       LdaNamedProperty r2, [1], [4]
         0x19370829377c @   18 : c3                Star1 
         0x19370829377d @   19 : 13 02             LdaConstant [2]
         0x19370829377f @   21 : c1                Star3 
         0x193708293780 @   22 : 5e f9 f8 f7 06    CallProperty1 r1, r2, r3, [6]
         0x193708293785 @   27 : 0e                LdaUndefined 
         0x193708293786 @   28 : a9                Return 
Constant pool (size = 3)
0x193708293735: [FixedArray] in OldSpace
 - map: 0x193708002205 <Map>
 - length: 3
           0: 0x193708202741 <String[7]: #console>
           1: 0x193708202769 <String[5]: #error>
           2: 0x19370800455d <String[5]: #Error>

Generator

解析賦值這樣使用迭代器的方式是下一節(jié)轉(zhuǎn)碼效率高的部分。
但是,針對(duì)Generator這樣顯式使用迭代器的,就是另一番情況了。

我們看一個(gè)最簡(jiǎn)單的Generator,我們只生成幾個(gè)數(shù)字:

let f1 = () => {
  let obj1 = {
    *[Symbol.iterator]() {
      yield 1;
      yield 2;
      yield 3;
    }
  };
  [...obj1];
};

我們看到,轉(zhuǎn)碼后的結(jié)果,不但定義了幾個(gè)函數(shù),還需要regeneratorRuntime運(yùn)行時(shí)的支持:

function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }

function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }

function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

var f1 = function f1() {
  var obj1 = {
    [Symbol.iterator]() {
      return /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
        return regeneratorRuntime.wrap(function _callee$(_context) {
          while (1) {
            switch (_context.prev = _context.next) {
              case 0:
                _context.next = 2;
                return 1;

              case 2:
                _context.next = 4;
                return 2;

              case 4:
                _context.next = 6;
                return 3;

              case 6:
              case "end":
                return _context.stop();
            }
          }
        }, _callee);
      })();
    }

  };

  _toConsumableArray(obj1);
};

如果將上面的代碼用Node運(yùn)行,會(huì)報(bào)錯(cuò):

var obj1 = _defineProperty({}, Symbol.iterator, /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
                                                               ^
ReferenceError: regeneratorRuntime is not defined

因?yàn)檫\(yùn)行庫(kù)沒(méi)有被引入進(jìn)來(lái),我們還得加個(gè)庫(kù),先install:

npm install --save @babel/polyfill

然后把庫(kù)引進(jìn)來(lái):

require("@babel/polyfill");
...
var f1 = function f1() {
    var obj1 = {
        [Symbol.iterator]() {
            return /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
...

這增加了多少代碼量,就留給讀者自己去算吧。

雖然說(shuō)class本質(zhì)上跟Function的語(yǔ)法糖也差不多,但是,Babel轉(zhuǎn)碼生成出來(lái)的代碼,可能比大多數(shù)同學(xué)想象的多。
我們看一個(gè)簡(jiǎn)單的例子:

class Code {
    constructor(source) {
      this.source = source;
    }
  }
  code1 = new Code("test1.js");

轉(zhuǎn)碼之后效果如下,Babel為我們生成了_createClass,_classCallCheck和_defineProperties三個(gè)函數(shù):

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); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var Code = /*#__PURE__*/_createClass(function Code(source) {
    _classCallCheck(this, Code);

    this.source = source;
});

code1 = new Code("test1.js");

依賴polyfill和runtime的內(nèi)置對(duì)象

我們知道,ES6新增了不少對(duì)象還有原有對(duì)象的新屬性。

比如你使用新增加的Set,Map,WeakSet,WeakMap等對(duì)象,或者是Number.isNaN這樣的新方法,Babel并沒(méi)有幫我們轉(zhuǎn)碼成ES5的語(yǔ)句。

那么,這些語(yǔ)句在老的游覽器是如何支持的呢?

答案大家可能已經(jīng)猜到了,就是我們之前Generator時(shí)用到的@babel/polyfill庫(kù)。Babel polyfill庫(kù)實(shí)際上是基于兩個(gè)開源的庫(kù):

  1. 一個(gè)是facebook的regenerator庫(kù),目前運(yùn)行時(shí)是一個(gè)700多行的文件:regenerator runtime .
  2. 另一個(gè)是core-js庫(kù),大部分的內(nèi)置對(duì)象的支持都靠它。

我們代碼寫成這樣:

Array.from(new Set([1, 2, 3, 2, 1]));
[1, [2, 3], [4, [5]]].flat(2);
Promise.resolve(32).then(x => console.log(x));

實(shí)際上Babel/runtime執(zhí)行的是這樣的:

import from from 'core-js-pure/stable/array/from';
import flat from 'core-js-pure/stable/array/flat';
import Set from 'core-js-pure/stable/set';
import Promise from 'core-js-pure/stable/promise';

from(new Set([1, 2, 3, 2, 1]));
flat([1, [2, 3], [4, [5]]], 2);
Promise.resolve(32).then(x => console.log(x));

轉(zhuǎn)碼效果更好

凡事皆有特例,從某些功能來(lái)講,也許轉(zhuǎn)碼實(shí)現(xiàn)更好。

解構(gòu)賦值

我們引用阮一峰老師的變量交換的的例子:

let f1 = () => {
  let x = 1;
  let y = 2;
  [x, y] = [y, x];
};

f1();

轉(zhuǎn)碼之后變成這樣:

var f1 = function f1() {
  var x = 1;
  var y = 2;
  var _ref = [y, x];
  x = _ref[0];
  y = _ref[1];
};

f1();

我們先看下轉(zhuǎn)碼之后的字節(jié)碼,有44個(gè)字節(jié):

         0xf1208293682 @    0 : 0d 01             LdaSmi [1]
         0xf1208293684 @    2 : c4                Star0 
         0xf1208293685 @    3 : 0d 02             LdaSmi [2]
         0xf1208293687 @    5 : c3                Star1 
         0xf1208293688 @    6 : 79 00 00 25       CreateArrayLiteral [0], [0], #37
         0xf120829368c @   10 : c0                Star4 
         0xf120829368d @   11 : 0c                LdaZero 
         0xf120829368e @   12 : c1                Star3 
         0xf120829368f @   13 : 0b f9             Ldar r1
         0xf1208293691 @   15 : 36 f6 f7 01       StaInArrayLiteral r4, r3, [1]
         0xf1208293695 @   19 : 0d 01             LdaSmi [1]
         0xf1208293697 @   21 : c1                Star3 
         0xf1208293698 @   22 : 0b fa             Ldar r0
         0xf120829369a @   24 : 36 f6 f7 01       StaInArrayLiteral r4, r3, [1]
         0xf120829369e @   28 : 19 f6 f8          Mov r4, r2
         0xf12082936a1 @   31 : 0c                LdaZero 
         0xf12082936a2 @   32 : 2f f8 03          LdaKeyedProperty r2, [3]
         0xf12082936a5 @   35 : c4                Star0 
         0xf12082936a6 @   36 : 0d 01             LdaSmi [1]
         0xf12082936a8 @   38 : 2f f8 05          LdaKeyedProperty r2, [5]
         0xf12082936ab @   41 : c3                Star1 
         0xf12082936ac @   42 : 0e                LdaUndefined 
         0xf12082936ad @   43 : a9                Return

上面更簡(jiǎn)潔的解構(gòu)需要多少個(gè)字節(jié)?

答案是189字節(jié),因?yàn)樯婕暗降鳎?/p>

         0xf120829376e @    0 : 0d 01             LdaSmi [1]
         0xf1208293770 @    2 : c4                Star0 
         0xf1208293771 @    3 : 0d 02             LdaSmi [2]
         0xf1208293773 @    5 : c3                Star1 
         0xf1208293774 @    6 : 79 00 00 25       CreateArrayLiteral [0], [0], #37
         0xf1208293778 @   10 : c1                Star3 
         0xf1208293779 @   11 : 0c                LdaZero 
         0xf120829377a @   12 : c2                Star2 
         0xf120829377b @   13 : 0b f9             Ldar r1
         0xf120829377d @   15 : 36 f7 f8 01       StaInArrayLiteral r3, r2, [1]
         0xf1208293781 @   19 : 0d 01             LdaSmi [1]
         0xf1208293783 @   21 : c2                Star2 
         0xf1208293784 @   22 : 0b fa             Ldar r0
         0xf1208293786 @   24 : 36 f7 f8 01       StaInArrayLiteral r3, r2, [1]
         0xf120829378a @   28 : b1 f7 03 05       GetIterator r3, [3], [5]
         0xf120829378e @   32 : 19 f7 f8          Mov r3, r2
         0xf1208293791 @   35 : 9f 07             JumpIfJSReceiver [7] (0xf1208293798 @ 42)
         0xf1208293793 @   37 : 65 bf 00 fa 00    CallRuntime [ThrowSymbolIteratorInvalid], r0-r0
         0xf1208293798 @   42 : c0                Star4 
         0xf1208293799 @   43 : 2d f6 01 07       LdaNamedProperty r4, [1], [7]
         0xf120829379d @   47 : c1                Star3 
         0xf120829379e @   48 : 12                LdaFalse 
         0xf120829379f @   49 : bf                Star5 
         0xf12082937a0 @   50 : 19 ff f2          Mov <context>, r8
         0xf12082937a3 @   53 : 0b f5             Ldar r5
         0xf12082937a5 @   55 : 96 21             JumpIfToBooleanTrue [33] (0xf12082937c6 @ 88)
         0xf12082937a7 @   57 : 11                LdaTrue 
         0xf12082937a8 @   58 : bf                Star5 
         0xf12082937a9 @   59 : 5d f7 f6 0d       CallProperty0 r3, r4, [13]
         0xf12082937ad @   63 : bb                Star9 
         0xf12082937ae @   64 : 9f 07             JumpIfJSReceiver [7] (0xf12082937b5 @ 71)
         0xf12082937b0 @   66 : 65 b7 00 f1 01    CallRuntime [ThrowIteratorResultNotAnObject], r9-r9
         0xf12082937b5 @   71 : 2d f1 02 0b       LdaNamedProperty r9, [2], [11]
         0xf12082937b9 @   75 : 96 0d             JumpIfToBooleanTrue [13] (0xf12082937c6 @ 88)
         0xf12082937bb @   77 : 2d f1 03 09       LdaNamedProperty r9, [3], [9]
         0xf12082937bf @   81 : bb                Star9 
         0xf12082937c0 @   82 : 12                LdaFalse 
         0xf12082937c1 @   83 : bf                Star5 
         0xf12082937c2 @   84 : 0b f1             Ldar r9
         0xf12082937c4 @   86 : 8a 03             Jump [3] (0xf12082937c7 @ 89)
         0xf12082937c6 @   88 : 0e                LdaUndefined 
         0xf12082937c7 @   89 : c4                Star0 
         0xf12082937c8 @   90 : 0b f5             Ldar r5
         0xf12082937ca @   92 : 96 21             JumpIfToBooleanTrue [33] (0xf12082937eb @ 125)
         0xf12082937cc @   94 : 11                LdaTrue 
         0xf12082937cd @   95 : bf                Star5 
         0xf12082937ce @   96 : 5d f7 f6 0f       CallProperty0 r3, r4, [15]
         0xf12082937d2 @  100 : bb                Star9 
         0xf12082937d3 @  101 : 9f 07             JumpIfJSReceiver [7] (0xf12082937da @ 108)
         0xf12082937d5 @  103 : 65 b7 00 f1 01    CallRuntime [ThrowIteratorResultNotAnObject], r9-r9
         0xf12082937da @  108 : 2d f1 02 0b       LdaNamedProperty r9, [2], [11]
         0xf12082937de @  112 : 96 0d             JumpIfToBooleanTrue [13] (0xf12082937eb @ 125)
         0xf12082937e0 @  114 : 2d f1 03 09       LdaNamedProperty r9, [3], [9]
         0xf12082937e4 @  118 : bb                Star9 
         0xf12082937e5 @  119 : 12                LdaFalse 
         0xf12082937e6 @  120 : bf                Star5 
         0xf12082937e7 @  121 : 0b f1             Ldar r9
         0xf12082937e9 @  123 : 8a 03             Jump [3] (0xf12082937ec @ 126)
         0xf12082937eb @  125 : 0e                LdaUndefined 
         0xf12082937ec @  126 : c3                Star1 
         0xf12082937ed @  127 : 0d ff             LdaSmi [-1]
         0xf12082937ef @  129 : bd                Star7 
         0xf12082937f0 @  130 : be                Star6 
         0xf12082937f1 @  131 : 8a 05             Jump [5] (0xf12082937f6 @ 136)
         0xf12082937f3 @  133 : bd                Star7 
         0xf12082937f4 @  134 : 0c                LdaZero 
         0xf12082937f5 @  135 : be                Star6 
         0xf12082937f6 @  136 : 10                LdaTheHole 
         0xf12082937f7 @  137 : a6                SetPendingMessage 
         0xf12082937f8 @  138 : bc                Star8 
         0xf12082937f9 @  139 : 0b f5             Ldar r5
         0xf12082937fb @  141 : 96 23             JumpIfToBooleanTrue [35] (0xf120829381e @ 176)
         0xf12082937fd @  143 : 19 ff f0          Mov <context>, r10
         0xf1208293800 @  146 : 2d f6 04 11       LdaNamedProperty r4, [4], [17]
         0xf1208293804 @  150 : 9e 1a             JumpIfUndefinedOrNull [26] (0xf120829381e @ 176)
         0xf1208293806 @  152 : b9                Star11 
         0xf1208293807 @  153 : 5d ef f6 13       CallProperty0 r11, r4, [19]
         0xf120829380b @  157 : 9f 13             JumpIfJSReceiver [19] (0xf120829381e @ 176)
         0xf120829380d @  159 : b8                Star12 
         0xf120829380e @  160 : 65 b7 00 ee 01    CallRuntime [ThrowIteratorResultNotAnObject], r12-r12
         0xf1208293813 @  165 : 8a 0b             Jump [11] (0xf120829381e @ 176)
         0xf1208293815 @  167 : ba                Star10 
         0xf1208293816 @  168 : 0c                LdaZero 
         0xf1208293817 @  169 : 1c f4             TestReferenceEqual r6
         0xf1208293819 @  171 : 98 05             JumpIfTrue [5] (0xf120829381e @ 176)
         0xf120829381b @  173 : 0b f0             Ldar r10
         0xf120829381d @  175 : a8                ReThrow 
         0xf120829381e @  176 : 0b f2             Ldar r8
         0xf1208293820 @  178 : a6                SetPendingMessage 
         0xf1208293821 @  179 : 0c                LdaZero 
         0xf1208293822 @  180 : 1c f4             TestReferenceEqual r6
         0xf1208293824 @  182 : 99 05             JumpIfFalse [5] (0xf1208293829 @ 187)
         0xf1208293826 @  184 : 0b f3             Ldar r7
         0xf1208293828 @  186 : a8                ReThrow 
         0xf1208293829 @  187 : 0e                LdaUndefined 
         0xf120829382a @  188 : a9                Return 
Constant pool (size = 5)
0xf1208293731: [FixedArray] in OldSpace
 - map: 0x0f1208002205 <Map>
 - length: 5
           0: 0x0f12082936fd <ArrayBoilerplateDescription PACKED_SMI_ELEMENTS, 0x0f12082936ed <FixedArray[2]>>
           1: 0x0f1208004e65 <String[4]: #next>
           2: 0x0f1208004441 <String[4]: #done>
           3: 0x0f1208005619 <String[5]: #value>
           4: 0x0f12080051dd <String[6]: #return>

兼容性還得再等一等

凡事皆有特例,從某些功能來(lái)講,也許轉(zhuǎn)碼實(shí)現(xiàn)更好。

Nullish運(yùn)算符

Nullish運(yùn)算符就是"??"運(yùn)算符,如果為null和undefined則取"??"后邊的值:

function greet(input) {
  return input ?? "Hello world";
}

翻譯成字節(jié)碼是9個(gè)字節(jié):

         0x94c082935da @    0 : 0b 03             Ldar a0
         0x94c082935dc @    2 : 9e 04             JumpIfUndefinedOrNull [4] (0x94c082935e0 @ 6)
         0x94c082935de @    4 : 8a 04             Jump [4] (0x94c082935e2 @ 8)
         0x94c082935e0 @    6 : 13 00             LdaConstant [0]
         0x94c082935e2 @    8 : a9                Return

轉(zhuǎn)碼之后的結(jié)果:

function greet(input) {
  return input !== null && input !== void 0 ? input : "Hello world";
}

翻譯成字節(jié)碼之后15個(gè)字節(jié):

         0x2a8a082935da @    0 : 0b 03             Ldar a0
         0x2a8a082935dc @    2 : 9a 0a             JumpIfNull [10] (0x2a8a082935e6 @ 12)
         0x2a8a082935de @    4 : 0b 03             Ldar a0
         0x2a8a082935e0 @    6 : 9c 06             JumpIfUndefined [6] (0x2a8a082935e6 @ 12)
         0x2a8a082935e2 @    8 : 0b 03             Ldar a0
         0x2a8a082935e4 @   10 : 8a 04             Jump [4] (0x2a8a082935e8 @ 14)
         0x2a8a082935e6 @   12 : 13 00             LdaConstant [0]
         0x2a8a082935e8 @   14 : a9                Return

"??"運(yùn)算符被v8譯成JumpIfUndefinedOrNull指令,轉(zhuǎn)碼了之后就沒(méi)有這待遇了,變成JumpIfNull和JumpIfUndefined兩條指令。

所以,只要瀏覽器支持的話,Nullish運(yùn)算符還是值得不轉(zhuǎn)碼的。

乘方運(yùn)算符

與Nullish一樣,乘方運(yùn)算符也是有指令支持的。這樣就節(jié)省了函數(shù)調(diào)用的開銷。

let f1 = x => {
  return x ** x;
};

f1(10);

因?yàn)橛蠩xp指令,一共6個(gè)字節(jié)就搞定了:

         0xb75082936be @    0 : 0b 03             Ldar a0
         0xb75082936c0 @    2 : 3e 03 00          Exp a0, [0]
         0xb75082936c3 @    5 : a9                Return

轉(zhuǎn)碼之后變成:

var f1 = function f1(x) {
  return Math.pow(x, x);
};

f1(10);

因?yàn)橛泻瘮?shù)調(diào)用,需要16個(gè)字節(jié)的指令:

         0xb7508293652 @    0 : 21 00 00          LdaGlobal [0], [0]
         0xb7508293655 @    3 : c3                Star1 
         0xb7508293656 @    4 : 2d f9 01 02       LdaNamedProperty r1, [1], [2]
         0xb750829365a @    8 : c4                Star0 
         0xb750829365b @    9 : 5f fa f9 03 03 04 CallProperty2 r0, r1, a0, a0, [4]
         0xb7508293661 @   15 : a9                Return 
Constant pool (size = 2)
0xb7508293621: [FixedArray] in OldSpace
 - map: 0x0b7508002205 <Map>
 - length: 2
           0: 0x0b75082028e5 <String[4]: #Math>
           1: 0x0b7508202aa1 <String[3]: #pow>

JSX

有一種情況下是沒(méi)法用原生的代碼而必須要轉(zhuǎn)碼的,這就是React JSX的情部況。

雖然要轉(zhuǎn)碼,但是不同的目標(biāo)帶來(lái)的代碼量也是有顯著不同的。

比如下面的代碼,這是典型的React Hooks用法:

import React, { useState } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

我們按iOS 9來(lái)轉(zhuǎn)碼:

const babel = require("@babel/core");
const generate = require("@babel/generator");

    let result3 = babel.transformSync(code, {
        targets: "iOS 9",
        sourceMaps: true,
        presets: ["@babel/preset-env", "@babel/preset-react"]
    });
    let str1 = result3.code;
    console.log(str1);

轉(zhuǎn)碼后的結(jié)果如下:

...
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }

function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }

function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }

function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }

function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }

function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }

function Example() {
  var _useState = (0, _react.useState)(0),
      _useState2 = _slicedToArray(_useState, 2),
      count = _useState2[0],
      setCount = _useState2[1];

  return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, "You clicked ", count, " times"), /*#__PURE__*/_react.default.createElement("button", {
    onClick: function onClick() {
      return setCount(count + 1);
    }
  }, "Click me"));
}

而按iOS 15為目標(biāo)來(lái)轉(zhuǎn)碼,因?yàn)橹С纸鈽?gòu),就不用生成那么多js代碼了:

function Example() {
    const [count, setCount] = (0, _react.useState)(0);
    return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("p", null, "You clicked ", count, " times"), /*#__PURE__*/_react.default.createElement("button", {
        onClick: () => setCount(count + 1)
    }, "Click me"));
}

總結(jié)

從前面的案例中,我們可以看到,除了像解構(gòu)引入了迭代這樣的結(jié)構(gòu)會(huì)變得復(fù)雜以外,大部分情況下,從源代碼和字節(jié)碼兩個(gè)方面看,如果可以不轉(zhuǎn)碼,更有利于v8提升性能。

尤其是不是簡(jiǎn)單轉(zhuǎn)碼就可以,還需要依賴于polyfill運(yùn)行時(shí)的功能,無(wú)論是從代碼庫(kù)大小和運(yùn)行速度上都不劃算。

總體來(lái)看,對(duì)ES6的出現(xiàn)我認(rèn)為是值得鼓勵(lì)的。技術(shù)是不斷向前發(fā)展的,瀏覽器支持與否只是一個(gè)時(shí)間問(wèn)題,我們可以試想,區(qū)區(qū)5年前做一個(gè)網(wǎng)站都還有支持IE6這種普遍需求,一個(gè)瀏覽器如果不支持flash插件,很多網(wǎng)站都會(huì)報(bào)錯(cuò)的。而今天這兩者都不知所蹤了。所以我們應(yīng)該對(duì)標(biāo)準(zhǔn)化的技術(shù)的普及抱有充足的信心。

分享到:
標(biāo)簽:ES6
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定