ES6語言的普及
2015年6月, ES2015(即 ECMAScript 6必尼、ES6) 正式發(fā)布勘究。ES2015 是該語言的一個顯著更新,也是自 2009年 ES5 標準確定后的第一個重大更新览露。伴隨著ES6的普及,大量的js框架都采用了最新的語法譬胎,并且也使前端開發(fā)大量采用工程化開發(fā)方式使用es6語法差牛。但是工程化前端開發(fā)由于其babel編譯的處理,已經(jīng)很好的把ES6的代碼編譯為ES5的版本堰乔,使得各種瀏覽器都能很好的兼容偏化。
瀏覽器的兼容性
然而純?yōu)g覽器端使用ES6語法還是存在瀏覽器支持度的差異,要特殊處理才能正常運行镐侯。
桌面端瀏覽器對ES2015的支持情況
- Chrome:51 版起便可以支持 97% 的 ES6 新特性侦讨。
- Firefox:53 版起便可以支持 97% 的 ES6 新特性。
- Safari:10 版起便可以支持 99% 的 ES6 新特性苟翻。
- IE:Edge 15可以支持 96% 的 ES6 新特性韵卤。
- Edge 14 可以支持 93% 的 ES6 新特性。(IE7~11 基本不支持 ES6)
詳細參見:http://kangax.github.io/compat-table/es6/
可以看到IE11又拖了后腿崇猫,對ES6徹底放棄沈条,由Edge 來支撐它的未來。
IE11下有效兼容ES6
那么如何讓純ES6腳本在IE11下運行呢诅炉,還是babel蜡歹,提供了有效的解決辦法
引入兩個腳本:
https://cdn.bootcss.com/babel-core/5.8.35/browser.min.js
該腳本轉(zhuǎn)換的是es6語法層面的語句
https://cdn.bootcss.com/babel-core/5.8.35/browser-polyfill.min.js
該腳本轉(zhuǎn)換了新語法的API屋厘,比如Set Map Promise等的方法
標記腳本塊的 type = "text/babel"
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>IE11 With ES6</title>
<script src="./browser-polyfill.min.js"></script>
<script src="./browser.min.js"></script>
<script type="text/babel">
const list = ['one', 'two', 'three'];
list.forEach((item, index) => {
alert(item + (index + 1));
});
let promise = new Promise(function (resolve, reject) {
alert('Promise');
resolve();
});
promise.then(function () {
alert('resolved.');
});
const items = new Set([1, 2, 3, 4, 5, 5, 5, 5]);
alert(items.size)
const map = new Map();
const k1 = ['a'];
const k2 = ['a'];
map.set(k1, 111).set(k2, 222);
alert(map.get(k2))
</script>
</head>
<body>
</body>
</html>
那么這里有兩個困惑:
第一:<script type="text/babel">
和我們平時用的<script type="text/javascript">
有什么區(qū)別。
第二:polyfill
到底干了什么
我們分別來說明下月而,我們來看一個未壓縮的代碼:https://cdn.bootcss.com/babel-core/5.8.38/browser.js
發(fā)現(xiàn)如下幾個代碼片段:
//頁面加載后汗洒,執(zhí)行runScripts方法
if (global.addEventListener) {
global.addEventListener("DOMContentLoaded", runScripts, false);
} else if (global.attachEvent) {
global.attachEvent("onload", runScripts);
}
var runScripts = function runScripts() {
var scripts = [];
//識別類型
var types = ["text/ecmascript-6", "text/6to5", "text/babel", "module"];
var index = 0;
/**
* Transform and execute script. Ensures correct load order.
*/
var exec = function exec() {
var param = scripts[index];
if (param instanceof Array) {
transform.run.apply(transform, param);
index++;
exec();
}
};
/**
* Load, transform, and execute all scripts.
*/
var run = function run(script, i) {
var opts = {};
if (script.src) {
transform.load(script.src, function (param) {
scripts[i] = param;
exec();
}, opts, true);
} else {
opts.filename = "embedded";
scripts[i] = [script.innerHTML, opts];
}
};
// Collect scripts with Babel `types`.
var _scripts = global.document.getElementsByTagName("script");
//按照類別加載
for (var i = 0; i < _scripts.length; ++i) {
var _script = _scripts[i];
if (types.indexOf(_script.type) >= 0) scripts.push(_script);
}
//執(zhí)行
for (i in scripts) {
run(scripts[i], i);
}
exec();
};
我想我們關注的text/babel
就在這里:var types = ["text/ecmascript-6", "text/6to5", "text/babel", "module"];
獲取頁面上標記為以上三項的腳步,然后用transform
庫進行加載和翻譯成ES5進行執(zhí)行景鼠。
那么polyfill
又干了什么呢仲翎,繼續(xù)閱讀代碼https://cdn.bootcss.com/babel-core/5.8.38/browser-polyfill.js
同樣定位到一段代碼:
$export($export.P, 'Array', {
// 22.1.3.10 / 15.4.4.18 Array.prototype.forEach(callbackfn [, thisArg])
forEach: $.each = $.each || methodize(createArrayMethod(0)),
// 22.1.3.15 / 15.4.4.19 Array.prototype.map(callbackfn [, thisArg])
map: methodize(createArrayMethod(1)),
// 22.1.3.7 / 15.4.4.20 Array.prototype.filter(callbackfn [, thisArg])
filter: methodize(createArrayMethod(2)),
// 22.1.3.23 / 15.4.4.17 Array.prototype.some(callbackfn [, thisArg])
some: methodize(createArrayMethod(3)),
// 22.1.3.5 / 15.4.4.16 Array.prototype.every(callbackfn [, thisArg])
every: methodize(createArrayMethod(4)),
// 22.1.3.18 / 15.4.4.21 Array.prototype.reduce(callbackfn [, initialValue])
reduce: createArrayReduce(false),
// 22.1.3.19 / 15.4.4.22 Array.prototype.reduceRight(callbackfn [, initialValue])
reduceRight: createArrayReduce(true),
// 22.1.3.11 / 15.4.4.14 Array.prototype.indexOf(searchElement [, fromIndex])
indexOf: methodize(arrayIndexOf),
// 22.1.3.14 / 15.4.4.15 Array.prototype.lastIndexOf(searchElement [, fromIndex])
lastIndexOf: function(el, fromIndex /* = @[*-1] */){
var O = toIObject(this)
, length = toLength(O.length)
, index = length - 1;
if(arguments.length > 1)index = Math.min(index, toInteger(fromIndex));
if(index < 0)index = toLength(length + index);
for(;index >= 0; index--)if(index in O)if(O[index] === el)return index;
return -1;
}
});
var createArrayReduce = function(isRight){
return function(callbackfn, memo){
aFunction(callbackfn);
var O = IObject(this)
, length = toLength(O.length)
, index = isRight ? length - 1 : 0
, i = isRight ? -1 : 1;
if(arguments.length < 2)for(;;){
if(index in O){
memo = O[index];
index += i;
break;
}
index += i;
if(isRight ? index < 0 : length <= index){
throw TypeError('Reduce of empty array with no initial value');
}
}
for(;isRight ? index >= 0 : length > index; index += i)if(index in O){
memo = callbackfn(memo, O[index], index, this);
}
return memo;
};
};
可以發(fā)現(xiàn)ployfill給Arrary添加了很多新方法,比如createArrayReduce
就是實現(xiàn)reduce
用的铛漓。
注意
引入以上兩個文件基本就解決了瀏覽器對ES6的大部分支持問題溯香。
不過再次強調(diào):即使使用了轉(zhuǎn)換工具,還是不建議在生產(chǎn)環(huán)境大量地使用瀏覽器對ES6支持度較低的新特性的特性浓恶。畢竟這是在線轉(zhuǎn)換后才執(zhí)行的玫坛,效率比較低。而且隨著瀏覽器對ES6的支持的變化包晰,這些轉(zhuǎn)換腳本也需要經(jīng)常更新湿镀,勢必對后期的維護帶來影響。