Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
compiler ecmascript6 to ecmascript5
npm install jsdc
Set
和Map
)请使用es6-shim
之类的库Iterator
,请确保有此扩展npm install
安装依赖homunculus
:https://github.com/army8735/homunculus[MIT License]
0b
或0B
开头的二进制将使用parseInt
转换:
var i = 0b010, j = 0B101
var i = parseInt("0b010", 2), j = parseInt("0B101", 2)
0o
或0O
开头的八进制也是如此(有人会用大写的字母O吗,和数字0根本看不出来区别):
var i = 0o456, j = 0O777
var i = parseInt("0o456", 8), j = parseInt("0O777", 8)
Unicode
编号大于0xFFFF
的字符将会转移成2个utf-8
拼接:
'\u{10000}'
'\ud800\udc00'
转义符也能正确识别:
'\\u{10000}'
'\\u{10000}'
赋值对象时Object
的同名属性可以简写:
var a = {o}
var a = {o:o}
方法也是:
var a = {o(){}}
var a = {o:function(){}}
甚至可以用[]
表明它是一个表达式:
var a = {
['a'+'b'] : 1
}
var a = function(){var _0={
_1: 1
};_0['a'+'b']=_0._1;delete _0._1;return _0}()
实现方法是先用个临时唯一变量替换掉表达式,最后再将它还原回来。
将var
申明迁移至最近的作用域起始处:
function() {
if(true) {
var a = 1;
let b = 2;
}
}
function() {var a;
if(true) {
a = 1;
let b = 2;
}
}
仅当必要时才迁移,否则保持原样(比如下面没有let
):
function() {
if(true) {
var a = 1;
}
}
示例中
let
和块级作用域尚未处理,后面会提到。
函数和var的性质一样,除了迁移还会改写为var形式:
{function a(){}}
var a;{a=function (){}}
必要时将{}
替换为function
作用域:
{
let a = 1;
function b(){}
}
!function() {
let a = 1;
function b(){}
}();
if
语句,iterator
语句和try
/catch
/finally
等也是,注意和纯{}
语句插入匿名函数位置的异同:
if(true) {
let a = 1;
}
if(true) {!function() {
let a = 1;
}();}
示例中
let
尚未做处理,后面会提到。
将let
和const
替换为var
:
let a = 1;
const b;
var a = 1;
var b;
注意和块级作用域的交互:
{
var a = 1;
let b;
const c = 1;
}
var a;!function() {
a = 1;
var b;
var c = 1;
}();
函数和
Generator
函数均默认块级作用域。
根据是否undefined
赋值,它可以有多个:
function method(a, b = 1) {
}
function method(a, b) {if(b ===void 0)b=1;
}
将扩展参数通过arguments
转换为数组:
function method(a, ...args) {
}
function method(a, args) {args = [].slice.call(arguments, 1);
}
方法执行则使用apply
调用:
fn(a, b, ...c)
fn.apply(this, [a,b].concat(function(){var _0=[],_1,_2=c[Symbol.iterator]();while(!(_1=_2.next()).done)_0.push(_1.value)return _0}()))
如果调用者是成员表达式,context将从this
变为主表达式:
Math.max(...a)
Math.max.apply(Math, [].concat(function(){var _0=[],_1,_2=c[Symbol.iterator]();while(!(_1=_2.next()).done)_0.push(_1.value)return _0}()))
在数组中则会自动展开,支持string预判断:
var codeUnits = [..."this is a string"];
var codeUnits = [...a];
var codeUnits = [].concat("this is a string".split(""));
var codeUnits = [].concat(Object.prototype.toString.call(a)=="[object String]"?a.split(""):a);
将模板转换为普通字符串,需要的情况下会包裹括号(确保运算符优先级正确性):
`template`
"template"
模板中的引号将被转义:
`"`
"\""
模板中的变量会被替换:
`${a}b`
(a + "b")
注意变量标识符$也可以被转义:
`\${a}b`
"\${a}b"
存储被循环体到临时引用:
for(a of b){
}
var _0=b;for(a of b){
}
将of
改为=
并添加;
补完循环:
for(a of b){
}
var _0=b;for(a =_0;;){
}
将赋值添加[Symbol.iterator]().next()
并添加.done
结束判断:
for(a of b){
}
var _0=b;for(a =_0[Symbol.iterator]().next();!a.done;a=_0.next()){
}
循环体内先赋值.value
:
for(a of b){
}
var _0=b;for(a =_0[Symbol.iterator]().next();!a.done;a=_0.next()){a=a.value;
}
var
语句同样处理:
for(var a of b){
}
var _0=b;for(var a =_0[Symbol.iterator]().next();!a.done;a=_0.next()){a=a.value;
}
将类声明改为function
声明:
class A{}
function A(){}
constructor
构造函数可省略,也可以显示声明:
class A{
constructor(a){this.a = a}
}
//此行是空行,请忽略:由于github会忽略前面的空白,所以用注释代替
function A(a){this.a = a}
注意行对应关系,省略的话行位置是
class
声明行,否则是constructor
声明行。
方法会改写成prototype
的原型方法:
class A{
method(){}
}
function A{}
A.prototype.method=function(){}
getter/setter会通过Object.defineProperty
巧妙地设置到原型上:
class A{
get b(){}
set c(d){}
}
function A(){}
Object.defineProperty(A.prototype, "b", {get :function(){}});
Object.defineProperty(A.prototype, "c", {set :function(d){}});
static
静态方法会附加在function
本身:
class A{
static F(){}
}
function A(){}
A.F=function(){}
采用最广泛的寄生组合式继承:
class A extends B{
constructor(){}
}
!function(){var _0=Object.create(B.prototype);_0.constructor=A;A.prototype=_0;}();
function A(){}
Object.keys(B).forEach(function(k){A[k]=B[k]});
开头会附加上一段
prototype
原型和constructor
构造器,标准的寄生组合式继承方法。
结尾会继承父类的静态属性。
super
关键字直接改写为父类引用:
class A extends B{
constructor(){super()}
}
!function(){var _0=Object.create(B.prototype);_0.constructor=A;A.prototype=_0;}();
function A(){B.call(this)}
Object.keys(B).forEach(function(k){A[k]=B[k]});
如果不是调用父类构造函数而是方法,则会这样:
class A extends B{
constructor(){super.a()}
}
!function(){var _0=Object.create(B.prototype);_0.constructor=A;A.prototype=_0;}();
function A(){B.prototype.a.call(this)}
Object.keys(B).forEach(function(k){A[k]=B[k]});
默认构造器函数则会自动调用super()
:
class A extends B{
}
function A(){B.call(this)}!function(){var _0=Object.create(B.prototype);_0.constructor=A;A.prototype=_0}();
Object.keys(B).forEach(function(k){A[k]=B[k]});
和函数表达式一样,class也可以有表达式:
var o = class{
method(){}
}
var o = function(){function _0(){}
_0.prototype.method = function(){}
return _0}()
由于表达式没有名字(也可以有),所以需要封装成立即执行的匿名函数并返回一个
class
声明。
有名字的话就用原有名字,否则依然临时唯一id。
注意匿名函数的结尾没有分号,因为本身是个
assignmentexpr
。
只要出现了module/import/export语句,就认为文件是个模块,用define
封装成AMD/CMD模块:
module circle from "a"
define(function(requrie,exports,module){module circle from "a"});
注意语句本身尚未做处理,下面会说明。为阅读方便,下面所有都省略了
define
封装。
也可以通过API设置来控制:
jsdc.define(wrap:Boolean):Boolean
module
转换为require
:
module circle from "a"
var circle=require("a");
import
也会转换为require
:
import "a"
require("a");
import
可以指定id:
import a from "a"
var a;!function(){var _0=require("a");a=_0.a}();
类似
_0
变量是自动生成的,数字会自动累加,且不会和已有变量冲突。
在冲突时会自动跳过:
import _0 from "a"
var _0;!function(){var _1=require("a");_0=_1.a}();
import
还可以指定多个id:
import a,b from "a"
var a;var b;!function(){var _0=require("a");a=_0.a;b=_0.b;}();
import
可以用{}
来赋值,注意里面as
声明变量名的方法:
import {a,b as c} from "a"
var a;var c;!function(){var _0=require("a");a=_0.a;c=_0.b;}();
export * from ""
会将模块的导出赋给module.exports:
export * from "a"
!function(){var _0=require("a");Object.keys(_0).forEach(function(k){module.exports[k]=temp[k];});}();
export
一个var
语句时会自动赋值同名变量:
export var a = 1
var a;exports.a=a = 1
export
一个方法或类时也一样:
export function a(){}
export class A{}
exports.a=a;function a(){}
exports.A=A;function A(){}
export default
会赋给exports.default
,这样在使用时会判断是否有default
属性:
export default a
import b from "a"
module.exports=a
var b=function(){var b=function(){var _0=require("a");return _0.hasOwnProperty("b")?_0.b:_0.hasOwnProperty("default")?_0.default:_0}()}()
注意单id会优先判断使用同名属性,退级使用
default
,最后模块本身
可以代替Array.map
方法:
var a = [for(k of o)k]
var a = function(){var k;var _0=[];for(k in o){k=o[k];_0.push(k)}return _0}()
注意再次出现的临时变量
_0
和上面提到的一致,不会冲突。
if
语句可以替代Array.filter
方法:
var a = [for(k of o)if(k)k]
var a = function(){var k;var _0=[];for(k in o){k=o[k];if(k)_0.push(k)}return _0}()
嵌套组合使用也是可以的:
var a = [for(a of b)for(c of a)if(c)c]
var a = function(){var a;var c;var _0=[];for(a in b){a=b[a];for(c in a){c=a[c];if(c)_0.push(c)}}return _0}()
转换为普通函数:
var a = v => v
var a = function(v) {return v}
括号形式的参数:
var a = (b, c) => b + c
var a = function(b, c) {return b + c}
带{}
的函数体:
var a = (b, c) => {return b - c}
var a = function(b, c) {return b - c}
yield
作为关键字只能出现在Generator
中,会被替换为return
:
function *a() {
yield
}
function *a() {
return
}
Generator
语句本身尚未做处理,后面会提到。
赋值语句后会加上一个临时唯一id,模拟下次调用next()
传入的一个参数:
function *a() {
var a = yield
}
function *a(_0) {
var a;return;a=_0
}
yield
的返回值将变成一个对象的value
,同时添加done
属性标明是否结束:
function *a() {
var a = yield 1
}
function *a(_0) {
var a;return {value:1,done:true};a=_0
}
它的实现比较复杂,首先是改写为普通函数:
function *a(){
yield 1
yield 2
}
function a(){
return{value:1,done:false}
return{value:2,done:true}
}
然后包裹:
function *a(){
yield 1
yield 2
}
var a=function(){return function(){return{next:a}};function a(){
return{value:1,done:false}
return{value:2,done:true}
}}();
这样每次调用它便能得到像es6中一样的一个具有
next()
方法的对象。
内部的a变量需要改写为一个唯一临时id(为什么后面会提到):
function *a(){
yield 1
yield 2
}
var a=function(){return function(){return{next:_0}};function _0(){
return{value:1,done:false}
return{value:2,done:true}
}}();
再次添加一个唯一临时id作为state标识,来为实现yield
功能做准备:
function *a(){
yield 1
yield 2
}
var a=function(){var _1;return function(){_1=0;return{next:_0}};function _0(){
return{value:1,done:false}
return{value:2,done:true}
}}();
当出现yield
语句时,添加while
和switch
语句来模拟顺序执行:
function *a(){
yield 1
yield 2
}
var a=function(){var _1;return function(){_1=0;return{next:_0}};function _0(){
while(1){switch(_1){case 0:_1=1;return{value:1,done:false}
case 1:_1=-1;return{value:1,done:true}}}
}}();
注意状态在
switch
各分支语句之间的跳转
同时函数里面的var
声明需要前置,以免每次调用next()
方法时又重新声明一遍失去了状态:
function *a(){
var a = 1;
yield a++;
yield a++;
}
var a=function(){var _1;return function(){_1=0;return{next:_0}};var a;function _0(){
while(1){switch(_1){case 0:a = 1;
_1=1;return{value:a++,done:false};
case 1:_1=-1;return{value:a++,done:true;}}}
}}();
函数则不需要前置。
注意函数内有个同名变量
a
,这就是前面为什么要改函数名的原因。
添加default
语句:
function *a(){
var a = 1;
yield a++;
yield a++;
}
var a=function(){var _0;return function(){_0=0;return{next:_1}};var a;function _1(_2){
while(1){switch(_0){case 0:a = 1;
_0=1;return{value:a++,done:false};case 1:
_0=-1;return{value:a++,done:true};default:return{done:true}}}
}}();
yield
还支持返回一个Generator
,这就是一个递归:
function *a(){
yield * b
}
var a=function(){var _0;return function(){_0=0;return{next:_1}};function _1(_2){
while(1){switch(_0){case 0:_0=1;var _3=b();if(!_3.done)_0=0;return _3;default:return{done:true}}}
}}();
表达式也一样,没有yield
则不会添加while
和switch
语句:
~function *(){
}
~function(){var _0;return function(){_0=0;return{next:_1}};function _1(){
}}()
var
声明变量时可以用数组:
var [a] = [1]
var a;!function(){var _0= [1];a=_0[0];}()
变量名会被前置,同时包裹执行一个匿名函数,将变量名赋值对应到正确的索引。
多个变量一样,注意逗号占位符:
var [a,b,,c] = [1]
var c;var b;var a;!function(){var _1= [1];a=_1[0];b=_1[1];c=_1[3]}()
也可以是对象:
var {a} = {"a":1}
var a;!function(){var _0= {"a":1};a=_0["a"]}()
注意变量名和键名要一致。
对象可以用:
号更改引用:
var {a,b:c} = {"a":1,"b":2}
var a;!function(){var _0= {"a":1,"b":2};a=_0["a"];c=_0["b"]}()
它们甚至可以互相嵌套递归:
var [a,{b},{c:[d]}] = [1,{"b":2},{"c":[3]}]
var d;var b;var a;!function(){var _0= [1,{"b":2},{"c":[3]}];a=_0[0];var _1=_0[1];b=_1["b"];var _2=_0[2];var _3=_2["c"];d=_3[0]}()
解构还允许在未定义的情况下默认赋值:
var [a=1] = []
var a;!function(){var _0= [];a=_0[0];if(_0.indexOf(a)!=0)a=1}()
表达式赋值也可以:
({a=1} = {})
(!function(){var _0= {};a=_0["a"];if(!_0.hasOwnProperty('a'))a=1;return _0}())
数组解构最后允许rest
运算符:
var [a, ...b] = [1, 2, 3]
var b;var a;!function(){var _0= [1, 2, 3];a=_0[0];b=_0.slice(1)}()
FAQs
compiler ecmascript6 to ecmascript5
The npm package jsdc receives a total of 13 weekly downloads. As such, jsdc popularity was classified as not popular.
We found that jsdc demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.