成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

ES6 + Webpack + React + Babel 如何在低版本瀏覽器上愉快的玩耍(上)

you_De / 2932人閱讀

摘要:起因某天,某測(cè)試說(shuō)這個(gè)頁(yè)面在下白屏,也白。。某前端開(kāi)發(fā)吭哧吭哧。。。一上午的時(shí)間就過(guò)去了,搞定了。第二天,某測(cè)試說(shuō)又白了。。某前端開(kāi)發(fā)吭哧吭哧。。。誰(shuí)用的,出來(lái)我保證削不屎你。原諒我不禁又黑了一把。

起因

某天,某測(cè)試說(shuō):“這個(gè)頁(yè)面在 IE8 下白屏,9也白。?!?/p>

某前端開(kāi)發(fā): 吭哧吭哧。。。一上午的時(shí)間就過(guò)去了,搞定了。

第二天,某測(cè)試說(shuō):“IE 又白了。?!?/p>

某前端開(kāi)發(fā): 吭哧吭哧。。。誰(shuí)用的 Object.assign,出來(lái)我保證削不屎你。

原諒我不禁又黑了一把 IE。

有人可能會(huì)想,都要淘汰了,還有什么好講的?

也許幾年后,確實(shí)沒(méi)用了,但目前我們的系統(tǒng)還是要對(duì) ie8+ 做兼容,因?yàn)榇_實(shí)還有個(gè)別用戶,盡管他沒(méi)朋友。。。

記錄下本次在 IE 下踩得坑,讓后面的同學(xué)能夠不再在這上面浪費(fèi)時(shí)間了。

經(jīng)過(guò) 測(cè)試

首先,看下面代碼(以下測(cè)試在 IE9)

class Test extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return 
{this.props.content}
; } } module.exports = Test;

這段代碼跑的妥妥的,沒(méi)什么問(wèn)題。

一般來(lái)說(shuō),babel 在轉(zhuǎn)換繼承時(shí),可能會(huì)出現(xiàn)兼容問(wèn)題,那么,再看這一段

class Test extends React.Component {
  constructor(props) {
    super(props);
  }
  test() {
      console.log("test");
  }
  render() {
    return 
{this.props.content}
; } } Test.defaultProps = { content: "測(cè)試" }; class Test2 extends Test { constructor(props) { super(props); this.test(); } } Test2.displayName = "Test2"; module.exports = Test2;

這段代碼同樣也可以正常運(yùn)行

也就是說(shuō)在上述這兩種情況下,不做任何處理(前提是已經(jīng)加載了 es5-shim/es5-sham),在 IE9 下都可以正常運(yùn)行。

然后我們?cè)倏聪聲?huì)跑掛的代碼

class Test extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      test: 1,
    };
  }
  test() {
      console.log(this.state.value);
  }
  render() {
    return 
{this.props.content}
; } } Test.defaultProps = { content: "測(cè)試" }; class Test2 extends Test { constructor(props) { super(props); // SCRIPT5007: 無(wú)法獲取屬性 "value" 的值,對(duì)象為 null 或未定義 this.test(); // SCRIPT5007: 無(wú)法獲取屬性 "b" 的值,對(duì)象為 null 或未定義 this.a = this.props.b; } } // undefined console.log(Test2.defaultProps); Test2.displayName = "Test2"; module.exports = Test2;

這段代碼在高級(jí)瀏覽器中是沒(méi)問(wèn)題的,在 IE9 中會(huì)出現(xiàn)注釋所描述的問(wèn)題

從這些問(wèn)題分析,可得出3個(gè)結(jié)論

在構(gòu)造函數(shù)里的定義的屬性無(wú)法被繼承

在構(gòu)造函數(shù)里不能使用 this.props.xx

類屬性或方法是無(wú)法被繼承的

也就是說(shuō),只要規(guī)避了這三個(gè)條件的話,不做任何處理(前提是已經(jīng)加載了 es5-shim/es5-sham),在 IE9 下都可以正常運(yùn)行。

第二點(diǎn),是完全可以避免的,切記在 constructor 直接使用 props.xxx, 不要再用 this.props.xxx

第三點(diǎn),也是可以完全避免的,因?yàn)閺睦碚撋蟻?lái)說(shuō),類屬性就不該被繼承,如果想使用父類的類屬性可以直接Test2.defaultProps = Test.defaultProps;

第一點(diǎn),可避免,但無(wú)法完全避免

原因

第一點(diǎn),有時(shí)是無(wú)法完全避免的,那么就要查詢?cè)?,才能找到解決方案

我們把 babel 轉(zhuǎn)義后的代碼放出來(lái)就能查出原因了

"use strict";

var _createClass = function () {
  ...
}();

function _classCallCheck(instance, Constructor) { 
  ...
}

function _possibleConstructorReturn(self, call) { 
  ...
  // 這個(gè)方法只是做了下判斷,返回第一個(gè)或第二參數(shù)
  return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { 
  ...; 
  // 這里的 _inherits 是通過(guò)將子類的原型[[prototype]]指向了父類,所以如果在高級(jí)瀏覽器下,子類的可以繼承到類屬性
  // 根本問(wèn)題也是出在這里,IE9 下既沒(méi)有 `setPrototypeOf` 也沒(méi)有 `__proto__`
  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; 
}

var Test = function (_React$Component) {
  ...
  return Test;
}(React.Component);

Test.defaultProps = {
  content: "測(cè)試"
};

var Test2 = function (_Test) {
  _inherits(Test2, _Test);

  function Test2(props) {
    _classCallCheck(this, Test2);
     // 這里的 this 會(huì)通過(guò) _possibleConstructorReturn,來(lái)獲取父類構(gòu)造函數(shù)里定義的屬性
     // _possibleConstructorReturn 只是做了下判斷,如果第二個(gè)參數(shù)得到了正確執(zhí)行,則返回執(zhí)行結(jié)果,否則返回第一個(gè)參數(shù),也就是子類的 this
     // 也就是說(shuō)問(wèn)題出在 Object.getPrototypeOf 
     // 在 _inherits 中將子類的原型指向了父類, 這里通過(guò) getPrototypeOf 來(lái)獲取父類,其實(shí)就是 _Test
     // Object.getPrototypeOf 不能正確的執(zhí)行,導(dǎo)致了子類無(wú)法繼承到在構(gòu)造函數(shù)里定義的屬性或方法,也無(wú)法繼承到類屬性或方法
    var _this2 = _possibleConstructorReturn(this, Object.getPrototypeOf(Test2).call(this, props));

    _this2.test();
    console.log(_this2.props.children);
    return _this2;
  }

  return Test2;
}(Test);

console.log(Test2.defaultProps);

Test2.displayName = "Test";

module.exports = Test2;

通過(guò)上述的代碼注釋,可以得出有兩處問(wèn)題需要解決

正確的獲取父類(解決無(wú)法繼承到在構(gòu)造函數(shù)里定義的屬性或方法)

正確的將子類的原型指向了父類(解決無(wú)法繼承到類屬性或方法)

解決方案

通過(guò)文檔的查詢,發(fā)現(xiàn)只要開(kāi)啟 es2015-classes 的 loose 模式即可解決第一個(gè)問(wèn)題

loose 模式

Babel have two modes:

A normal mode follows the semantics of ECMAScript 6 as closely as possible.

A loose mode produces simpler ES5 code.

Babel 有兩種模式:

盡可能符合 ES6 語(yǔ)義的 normal 模式。

提供更簡(jiǎn)單 ES5 代碼的 loose 模式。

盡管官方是更推薦使用 normal 模式,但為了兼容 IE,我們目前也只能開(kāi)啟 loose 模式。

在 babel6 中,主要是通過(guò) babel-preset-2015 這個(gè)插件,來(lái)進(jìn)行轉(zhuǎn)義的
我們看下 babel-preset-2015

 plugins: [
    require("babel-plugin-transform-es2015-template-literals"),
    require("babel-plugin-transform-es2015-literals"),
    require("babel-plugin-transform-es2015-function-name"),
    ...
    require("babel-plugin-transform-es2015-classes"),
    ...
    require("babel-plugin-transform-es2015-typeof-symbol"),
    require("babel-plugin-transform-es2015-modules-commonjs"),
    [require("babel-plugin-transform-regenerator"), { async: false, asyncGenerators: false }],
  ]

是一堆對(duì)應(yīng)轉(zhuǎn)義的插件,從命名上也可看出了大概,比如 babel-plugin-transform-es2015-classes 就是做類的轉(zhuǎn)義的,也就是我們只需把它開(kāi)啟 loose 模式,即可解決我們的一個(gè)問(wèn)題

[require("babel-plugin-transform-es2015-classes"), {loose: true}],

看下開(kāi)啟了 loose 模式的代碼,你會(huì)發(fā)現(xiàn)它的確更接近 ES5

var Test = function (_React$Component) {
  ...
  // 這里是 ES5 的寫法
  Test.prototype.test = function test() {
    console.log(this.state.value);
  };
  /* normal 模式是這樣的
  {
    key: "test",
    value: function test() {
      console.log(this.state.value);
    }
  }
  */
  return Test;
}(React.Component);

var Test2 = function (_Test) {
  _inherits(Test2, _Test);

  function Test2(props) {
    _classCallCheck(this, Test2);
    // 這里直接拿到了父類 _Test, 即解決了無(wú)法繼承到在構(gòu)造函數(shù)里定義的屬性或方法
    var _this2 = _possibleConstructorReturn(this, _Test.call(this, props));

    _this2.test();
    return _this2;
  }

  return Test2;
}(Test);

我們可以通過(guò)去安裝 babel-preset-es2015-loose, 這個(gè)插件來(lái)開(kāi)啟 loose 模式。

但從我們團(tuán)隊(duì)的 老司機(jī) 口中

得到了一個(gè)更好插件babel-preset-es2015-ie,看下這個(gè)插件的代碼,發(fā)現(xiàn)它和原來(lái)的 babel-preset-2015 只有兩行區(qū)別

[
  [require("babel-plugin-transform-es2015-classes"), {loose: true}],
  require("babel-plugin-transform-proto-to-assign"),
]

剛好解決我們上述碰到的兩個(gè)問(wèn)題

這個(gè) babel-plugin-transform-proto-to-assign 插件會(huì)生成一個(gè) _defaults 方法來(lái)處理原型

function _inherits(subClass, superClass) { 
  ...; 
  if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : _defaults(subClass, superClass);
}
function _defaults(obj, defaults) {
 var keys = Object.getOwnPropertyNames(defaults);
  for (var i = 0; i < keys.length; i++) {
   var key = keys[i]; 
   var value = Object.getOwnPropertyDescriptor(defaults, key);
    if (value && value.configurable && obj[key] === undefined) {
     Object.defineProperty(obj, key, value); 
     } 
   }
  return obj;
}

這個(gè)插件正確的將子類的原型指向了父類(解決無(wú)法繼承到類屬性或方法)

總結(jié)

本文講述低版本瀏覽器報(bào)錯(cuò)的原因和解決方案

一方面是提示下在構(gòu)造函數(shù)里不要使用 this.props.xx

另一方面也對(duì)繼承的機(jī)制有了更好的理解

在這次項(xiàng)目中發(fā)現(xiàn)在低版本瀏覽器跑不起來(lái)的兩點(diǎn)主要原因:

SCRIPT5007: 無(wú)法獲取屬性 xxx 的值,對(duì)象為 null 或未定義,這種情況一般是組件繼承后,無(wú)法繼承到在構(gòu)造函數(shù)里定義的屬性或方法,同樣類屬性或方法也同樣無(wú)法繼承

SCRIPT438: 對(duì)象不支持 xxx 屬性或方法,這種情況一般是使用了 es6、es7 的高級(jí)語(yǔ)法,Object.assgin Object.keys 等,這種情況在移動(dòng)端的一些 ‘神機(jī)’ 也一樣會(huì)掛。

第一點(diǎn)本文已經(jīng)分析,預(yù)知第二點(diǎn)講解請(qǐng)見(jiàn)下篇。

備注:下篇會(huì)主要介紹下如何讓 用了 Object.assign 的那位同學(xué)可以繼續(xù)用,又不會(huì)被削。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80399.html

相關(guān)文章

  • ES6 + Webpack + React + Babel 如何在低版本覽器愉快玩耍(下)

    摘要:在上篇,我們主要拋出了兩個(gè)問(wèn)題,并給出了第一個(gè)問(wèn)題的解決方案。沒(méi)有的實(shí)例方法可以采用方案三委屈下。放棄模式,放棄上篇中提到了開(kāi)啟了模式來(lái)解決低版本瀏覽器無(wú)法繼承到在構(gòu)造函數(shù)里定義的屬性或方法。 回顧 起因: 某天,某測(cè)試說(shuō):這個(gè)頁(yè)面在 IE8 下白屏,9也白。。某前端開(kāi)發(fā): 吭哧吭哧。。。一上午的時(shí)間就過(guò)去了,搞定了。第二天,某測(cè)試說(shuō):IE 又白了。。某前端開(kāi)發(fā): 嘿咻嘿咻。。。誰(shuí)用的...

    Freelander 評(píng)論0 收藏0
  • React+Webpack+ES6 兼容低版本覽器(IE9)解決方案

    摘要:本文記錄如下起因在準(zhǔn)備提測(cè)的那天,順便打開(kāi)看一眼注意,這里是原生不是用模擬的,排查后發(fā)現(xiàn),原來(lái)是因?yàn)闃?gòu)造函數(shù)中使用了。簡(jiǎn)寫如下老司機(jī)們肯定能一眼發(fā)現(xiàn)問(wèn)題構(gòu)造函數(shù)中不應(yīng)該使用而是傳入的應(yīng)該改為改正之后,問(wèn)題確實(shí)解決了。 雖然過(guò)了兼容IE6的噩夢(mèng)時(shí)代,IE依舊陰魂不散,因?yàn)槟憧赡苓€要兼容IE9。在ES6已經(jīng)普及的今天,用ES6寫react已經(jīng)成了標(biāo)配。但是babel編譯的js語(yǔ)法,由于某些...

    hzc 評(píng)論0 收藏0
  • React+Webpack+ES6 兼容低版本覽器(IE9)解決方案

    摘要:本文記錄如下起因在準(zhǔn)備提測(cè)的那天,順便打開(kāi)看一眼注意,這里是原生不是用模擬的,排查后發(fā)現(xiàn),原來(lái)是因?yàn)闃?gòu)造函數(shù)中使用了。簡(jiǎn)寫如下老司機(jī)們肯定能一眼發(fā)現(xiàn)問(wèn)題構(gòu)造函數(shù)中不應(yīng)該使用而是傳入的應(yīng)該改為改正之后,問(wèn)題確實(shí)解決了。 雖然過(guò)了兼容IE6的噩夢(mèng)時(shí)代,IE依舊陰魂不散,因?yàn)槟憧赡苓€要兼容IE9。在ES6已經(jīng)普及的今天,用ES6寫react已經(jīng)成了標(biāo)配。但是babel編譯的js語(yǔ)法,由于某些...

    alphahans 評(píng)論0 收藏0
  • create-react-app 2.0版本如何啟用裝飾器語(yǔ)法

    摘要:簡(jiǎn)稱已經(jīng)更新之版本也更新至版本裝飾器語(yǔ)法雖然還不是標(biāo)準(zhǔn)但是借助于也能在項(xiàng)目里愉快的玩耍時(shí)代如何啟用裝飾器語(yǔ)法呢我們依舊采用的是通過(guò)劫持對(duì)象達(dá)到修改的目的修改安裝裝飾器語(yǔ)法所需的插件也可以順帶升級(jí)在項(xiàng)目 create-react-app(簡(jiǎn)稱cra)已經(jīng)更新之2.0.3版本, babel也更新至7.x版本, JavaScript裝飾器語(yǔ)法雖然還不是標(biāo)準(zhǔn), 但是借助于babel, 也能在項(xiàng)...

    Rindia 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<