判断浏览器对ES6的支持情况

 es-checker 是一个检查ES6支持的库,github: https://github.com/ruanyf/es-checker

下面我把这个库主要的逻辑简单讲一下,首先在es-checker/lib/api.js定义了api,包含了ES6的新特性:

var api = {
  letConst: { passes: "'use strict'; let a; const b = 2;" },
  letLoop: { passes: "'use strict'; for(let i in {}){}; for(let i=0;;){break}" },
  constLoop: { passes: "'use strict'; for(const i in {}){}; for (const i=0;;){break}" },
  defaultParameter: { passes: "'use strict'; function a(b=2){}" },
  spreadRest: { passes: "'use strict'; var a = [1,2]; +function b(...c){}(...a);" },
  destructuring: { passes: "'use strict'; var a = [1,2], [b,c] = a, d = {e:1,f:2}, {e:E,f} = d;" },
  parameterDestructuring: { passes: "'use strict'; function a({b,c}){}" },
  templateString: { passes: "'use strict'; var a = 1, b = `c${a}d`;" },
  forOf: { passes: "'use strict'; for (var a of [1]) {}" },
  arrow: { passes: "'use strict'; var a = () => {};" },
  generator: { passes: "'use strict'; function *a(){ yield; }" },
  conciseMethodProperty: { passes: "'use strict'; var a = 1, b = { c(){}, a };" },
  computedProperty: { passes: "'use strict'; var a = 1, b = { ['x'+a]: 2 };" },
  moduleExport: { passes: "'use strict'; export var a = 1;" },
  moduleImport: { passes: "'use strict'; import {a} from 'b';" },
  classes: { passes: "'use strict'; class Foo {}; class Bar extends Foo {};" },
  numericLiteral: { passes: "'use strict'; var a = 0o1, b = 0b10;" },
  oldOctalLiteral: { fails: "'use strict'; var a = 01;" },
  symbol: { passes: "'use strict'; var a = Symbol('b');" },
  symbolImplicitCoercion: { dependencies: ["symbol"], fails: "'use strict'; var a = Symbol('a'); a + '';" },
  unicodeEscape: { passes: "'use strict'; var a = '\\u{20BB7}';" },
  unicodeIdentifier: { passes: "'use strict'; var \\u{20BB7};" },
  unicodeRegExp: { passes: "'use strict'; var a = /\\u{20BB7}/u;" },
  stickyRegExp: { passes: "'use strict'; var a = /b/y;" },
  letTDZ: { dependencies: ["letConst"], fails: "'use strict'; a = 1; let a;" },
  letLoopScope: { dependencies: ["letLoop","forOf"], passes: "'use strict'; var x=[],i=0;for(let i=2;i<3;i++){x.push(function(){return i})};for(let i in {3:0}){x.push(function(){return i})};for(let i of [4]){x.push(function(){return i})};if(x[0]()*x[1]()*x[2]()!=24) throw 0;" },
  constRedef: { dependencies: ["letConst"], fails: "'use strict'; const a = 1; a = 2;" },
  objectProto: { passes: "'use strict'; var a = { b: 2 }, c = { __proto__: a }; if (c.b !== 2) throw 0;" },
  objectSuper: { passes: "'use strict'; var a = { b: 2 }, c = { d() { return super.b; } }; Object.setPrototypeOf(c,a); if (c.d() !== 2) throw 0;" },
  extendNatives: { dependencies: ["class"], passes: "'use strict'; class Foo extends Array { }; var a = new Foo(); a.push(1,2,3); if (a.length !== 3) throw 0;" },
  TCO: { passes: "'use strict'; +function a(b){ if (b<6E4) a(b+1); }(0);" },
  functionNameInference: { passes: "'use strict'; var a = { b: function(){} }; if (a.b.name != 'b') throw 0;" },
  ObjectStatics: { is: "'use strict'; return ('getOwnPropertySymbols' in Object) && ('assign' in Object) && ('is' in Object);" },
  ArrayStatics: { is: "'use strict'; return ('from' in Array) && ('of' in Array);" },
  ArrayMethods: { is: "'use strict'; return ('fill' in Array.prototype) && ('find' in Array.prototype) && ('findIndex' in Array.prototype) && ('entries' in Array.prototype) && ('keys' in Array.prototype) && ('values' in Array.prototype);" },
  TypedArrays: { is: "'use strict'; return ('ArrayBuffer' in global) && ('Int8Array' in global) && ('Uint8Array' in global) && ('Int32Array' in global) && ('Float64Array' in global);" },
  TypedArrayStatics: { dependencies: ["TypedArrays"], is: "'use strict'; return ('from' in Uint32Array) && ('of' in Uint32Array);" },
  TypedArrayMethods: { dependencies: ["TypedArrays"], is: "'use strict'; var x = new Int8Array(1); return ('slice' in x) && ('join' in x) && ('map' in x) && ('forEach' in x);" },
  StringMethods: { is: "'use strict'; return ('includes' in String.prototype) && ('repeat' in String.prototype);" },
  NumberStatics: { is: "'use strict'; return ('isNaN' in Number) && ('isInteger' in Number);" },
  MathStatics: { is: "'use strict'; return ('hypot' in Math) && ('acosh' in Math) && ('imul' in Math);" },
  collections: { is: "'use strict'; return ('Map' in global) && ('Set' in global) && ('WeakMap' in global) && ('WeakSet' in global);" },
  Proxy: { is: "'use strict'; return ('Proxy' in global);" },
  Promise: { is: "'use strict'; return ('Promise' in global);"},
  Reflect: { is: "'use strict'; return ('Reflect' in global);" },
};

在es-checker/lib/runtest.js中验证:

function runTest(key){
  if (key === 'class') key = 'classes';
  if (supports._api[key].dependencies) {
    for(var i = 0; i < supports._api[key].dependencies.length; i++){
      var depKey = supports._api[key].dependencies[i];
      if (runTest(depKey) === false) return false;
    }
  }

  if (supports._api[key].passes) {
    return tryPassFail(supports._api[key].passes);
  } else if (supports._api[key].fails) {
    return !tryPassFail(supports._api[key].fails);
  } else if (supports._api[key].is) {
    return tryReturn(supports._api[key].is);
  } else if (supports._api[key].not) {
    return !tryReturn(supports._api[key].not);
  }
}

function tryPassFail(code) {
  try {
    runIt(code);
    return true;
  }
  catch (err) {
    return false;
  }
}

function tryReturn(code) {
  try {
    return runIt(code);
  }
  catch (err) {
    return false;
  }
}

function runIt(code) {
  return (new Function(code))();
}

其中主要是用 runTest 函数进行判断,并全部通过 try catch 语句调用 runIt 中 new Function 执行api中定义的测试字符串

new Function(code)

判断结果,针对不同类型的判断略有不同.

如果为了简化浏览器段的开发,可以直接把上面的按需求合到一起,来判断自己所用到的新特性在浏览器中是否能支持.

直接检测自己的浏览器可以用该库的 demo: http://ruanyf.github.io/es-checker/

浏览器的ES情况可以看一下 http://kangax.github.io/compat-table/es6/

IE11基本不支持ES6,只能支持ES5,其余浏览器没问题,兼容情况要自己考虑一下了.

猜你喜欢

转载自my.oschina.net/zhupengdaniu/blog/1803204