一种JavaScript代码转译方法及装置与流程

文档序号:12119482阅读:304来源:国知局
一种JavaScript代码转译方法及装置与流程

本申请涉及计算机应用技术领域,尤其涉及一种JavaScript代码转译方法及装置。



背景技术:

JavaScript一种直译式脚本语言,目前已经被广泛用于Web应用开发,常用来为网页添加各种动态功能,为用户提供更流畅美观的浏览效果。ECMAScript是ECMA(European Computer Manufacturers Association,欧洲计算机制造商协会)制订的一种开放的JavaScript语言规范,自ECMAScript 3.0版本在1999年发布后,已经成为JavaScript的国际通用标准。目前主流的版本是在2011年发布的ECMAScript 5.1版本(下文简称为ES5),而ECMAScript的第六个版本(下文简称ES6)也已经在2015年6月17日正式发布。

ES6在ES5的基础上做了重大改进,ES6增添了许多新特性,例如对类(class)的支持、对模块(module)的支持等等,许多开发人员已经开始尝试使用ES6来进行应用的开发。然而,对于热衷于使用语言最新特性的开发人员而言,需要面对一个实际的情况是:截止到发布日期,无论是浏览器环境还是服务器环境,都还没有一款完全支持ES6的JavaScript代理,因此目前对于使用ES6规范开发的应用,需要使用转译器(Transpiler)将ES6代码转译为ES5代码,以便所开发的应用能够在现有的Web环境中正常使用,转译器的工作原理示意图如图1所示。

Babel和Traceur是开发人员目前常用的两种转译器,两者均可以实现ES6代码到ES5代码的转译功能,但是转译的结果只能兼容到较新的浏览器版本, 而对于一些早期的浏览器版本,例如IE8,则无法正常使用转译后的部分ES5代码。



技术实现要素:

针对上述技术问题,本申请提供一种JavaScript代码转译方法及装置,技术方案如下:

根据本申请的第一方面,提供一种JavaScript代码转译方法,该方法包括:

对待转译的ES6代码段进行解析;

根据解析结果,确定所述待转译代码段中的get/set方法声明代码部分,所述get/set方法包括:set方法或get方法;

将所述get/set方法所属类的class声明代码转译为function声明代码;

将所述get/set方法的声明代码转译为用于执行以下操作的功能代码:

创建一DOM对象;

将“this”关键字所指向对象的属性复制到所述DOM对象上;

利用ES5的对象属性定义方法,将所述get/set方法定义到所述DOM对象上;

以所述DOM对象作为返回值。

根据本申请的第二方面,提供一种JavaScript代码转译装置,该装置包括:

解析模块,用于对待转译的ES6代码段进行解析;

定位模块,用于根据解析结果,确定所述待转译代码段中的get/set方法声明代码部分,所述get/set方法包括:set方法或get方法;

类声明转译模块,用于将所述get/set方法所属类的class声明代码转译为function声明代码;

get/set声明转译模块,用于将所述get/set方法的声明代码转译为用于执行以下操作的功能代码:

创建一DOM对象;

将“this”关键字所指向对象的属性复制到所述DOM对象上;

利用ES5的对象属性定义方法,将所述get/set方法定义到所述DOM对象上;

以所述DOM对象作为返回值。

考虑到ES6中class在ES5中被转译为function,本申请实施例所提供的技术方案,利用早期浏览器版本对DOM对象get/set方法的支持特性,通过创建DOM对象,将function上的所有属性和方法复制到该DOM对象上,然后借助function的return返回值来返回该DOM对象,从而得到能够在早期浏览器版本中正确运行的类的get/set方法代码。

应当理解的是,以上的一般描述和后文的细节描述仅是示例性和解释性的,并不能限制本申请。

附图说明

为了更清楚地说明本申请实施例或现有技术中的技术方案,下面将对实施例或现有技术描述中所需要使用的附图作简单地介绍,显而易见地,下面描述中的附图仅仅是本申请中记载的一些实施例,对于本领域普通技术人员来讲,还可以根据这些附图获得其他的附图。

图1是JavaScript代码转译工作原理示意图;

图2是本申请的JavaScript代码转译方法的流程示意图;

图3是本申请的代码解析结果示意图;

图4是本申请的JavaScript代码转译装置的结构示意图。

具体实施方式

为了使本领域技术人员更好地理解本申请中的技术方案,下面将结合本申请实施例中的附图,对本申请实施例中的技术方案进行详细地描述,显然,所描述的实施例仅仅是本申请一部分实施例,而不是全部的实施例。基于本申请中的实施例,本领域普通技术人员所获得的所有其他实施例,都应当属于本申请保护的范围。

ES6新增了对类(class)的支持,其中class语法主要包括以下6方面特点:class类声明、extends继承声明、constructor构造函数声明、普通方法声明、static静态方法声明、get/set方法声明。目前,前5种语法的ES6到ES5代码转译均已经被Babel和Traceur实现,并且转译结果能够良好兼容于各类主流浏览器。但是get/set方法声明的转译结果只能兼容到IE9以上的版本、以及其他浏览器(例如Chrome、Firefox、Safari、Opera等)的较新版本,考虑到IE浏览器的特殊性—与主流操作系统捆绑、用户数量大且更新进程缓慢,使用IE8及以下版本的用户数量依然较多,如何保证这部分用户也能够正常使用转译后的ES5代码仍然具有较大的实际意义。

下面首先对现有技术的ES6到ES5代码转译方法做简单说明:

对于ES6中的class,在ES5中可以用function来替代,一个class就是一个function,例如:

ES6代码:

class A{}

转译后的ES5代码为:

function A(){}

对于ES6中的get/set方法,如果只考虑IE9以上的IE以及其他主流浏览器的较新版本,由于在这些浏览器中实现了原生get/set,所以只需要利用ES5内置的对象属性定义方法做等价直译即可,具体而言,使用对象属性定义方法中的Object.defineProperty(object,propertyName,descriptor)方法,该方法接收3个参数:

object:定义的对象;

propertyName:定义的名称;

descriptor:定义的内容;

返回值为定义后的对象。

在进行代码转译时,将get/set方法所属类的原型对象、get/set方法的声明名称、get/set方法的声明内容分别对应于上述3个参数传入即可,例如:

1)get方法的ES6代码:

class A{

get t(){/*声明内容*/}

}

转译后的ES5代码为:

function A(){}

Object.defineProperty(A.prototype,‘t’,function(){/*声明内容/});

2)set方法的ES6代码:

class A{

set t(v){/*声明内容*/}

}

转译后的ES5代码为:

function A(){}

Object.defineProperty(A.prototype,‘t’,function(v){/*声明内容/});;

然而在IE8等早期浏览器版本中,由于没有对普通JavaScript对象实现原生get/set方法,如果直接采用上述方法进行等价直译,将会直接导致错误而无法运行。

发明人通过对现有技术的分析发现:ES5内置的对象属性定义方法中,object参数除了支持普通JavaScript对象之外,还支持DOM对象。而IE8等早期浏览器版本中,虽然没有普通JavaScript对象实现get/set方法,但是却对DOM对象实现了实现get/set方法,利用这一特性,可以绕道在这些浏览器版本中实现类的get/set:首先创建一个DOM对象,考虑到ES6中class在ES5中被转译为function,因此将function上的所有属性和方法复制到该DOM对象上,然后借助function的return返回值来返回该DOM对象,从而实现类的get/set方法。

图2所示,为本申请提供的JavaScript代码转译方法的流程图,该方法可以包括以下步骤:

S101,对待转译的ES6代码段进行解析,根据解析结果,确定所述待转译代码段中的get/set方法声明代码部分。

由于set方法和get方法本质上是一致的,为描述方便,在本申请中均以 “get/set方法”的形式进行说明,不再单独特指get方法或set方法;

在本步骤中,可以使用任意现有的代码解析技术,对待转译的ES6代码段进行解析,以homunculus解析为例,可以得到如图3所示的抽象语法树(AST)。通过遍历AST寻找classdecl(类声明)节点,进一步根据bindid节点可以确定类名。

找到classdecl节点下的classbody节点,其下的叶子节点可能有若干个classelem(类元素)节点。如果一个classelem节点下仅有一个method节点,则是普通元素声明,本申请仅考虑普通元素声明的情况:如果method节点的第一个子节点为get或set,则能够定位get/set方法声明代码段。进一步可以确定get/set方法的声明名称、get/set方法的声明内容,以及get/set方法的所属类。

可以理解的是,图3所示的代码解析结果仅用于示意性说明,本领域技术人员可以实际需要选择任意可用的方法对待转译的ES6代码段进行解析。

S102,将get/set方法所属类的class声明代码转译为function声明代码;

在本步骤中,利用现有的转译方法将get/set方法所属类的class声明代码转译为function声明代码,例如:

ES6类声明代码:

class A{}

转译后的ES6代码为:

function A(){}

S103,将get/set方法的声明代码转译为利用DOM实现get/set的代码。

这里的“利用DOM实现get/set的代码”用于执行以下操作:

创建一DOM对象;

将“this”关键字所指向对象的属性复制到所述DOM对象上;

利用ES5的对象属性定义方法,将get/set方法定义到所述DOM对象上;

以所述DOM对象作为返回值。

下面结合具体的代码转译实例,对上述方法进行说明:

假设待转译的ES6代码为:

class A{

get b(){/*声明内容*/}

}

继承是类的一个重要的特性,如果不考虑继承,则利用DOM实现get/set相对简单,下面先对不考虑继承情况下的实现方法进行说明:

用for in预计遍历“this”,将“this”关键字所指向对象的属性复制一个新创建的DOM对象上,考虑到IE8浏览器不支持constructor属性的复制,因此这里一种优选的实施方式是在复制时排除constructor属性,即将“this”关键字所指向对象的除constructor之外的属性复制到所述DOM对象上,以避免无效操作。

然后利用ES5内置的对象属性定义方法中的Object.defineProperty方法将get/set方法的声明名称、声明内容定义到DOM对象上。

实现上述操作的ES5代码示意如下:

上述代码中的div即为创建的DOM对象,Object.defineProperty方法传入的3个参数分别为:DOM对象名称、get/set方法的声明名称、get/set方法的声明内容。最终返回值为定义后的DOM对象。

如果考虑继承,则需要在上述方法的基础上,进一步解决两个问题:

a)获得当前类的父类(如果存在)的get/set属性,和当前类自身的get/set属性合并;

b)保存合并结果,以便当前类的子类(如果存在)继承。

解决思路如下:

约定一个变量名,用于将父类的get/set传递给子类;

创建一临时对象,先将get/set方法所属类的父类的属性从约定变量中复制到该临时对象上,再将get/set方法的声明名称、声明内容赋值给该临时对象, 实现父类get/set和当前类get/set的合并;

利用临时对象的当前内容对约定变量进行更新,从而为get/set方法所属类的子类保存上述合并结果,以便后续继承。

实现上述操作的ES5代码示意如下:

在上述代码中,div为DOM对象,gs为临时对象,约定变量名__gs用于将父类的get/set传递给子类。区别于不考虑继承情况的操作流程包括:

创建空对象gs;

将类A的父类的属性从约定变量__gs中复制到gs上,如果A不存在父类,则该步骤不生效;

再将get/set方法的声明名称、声明内容赋值该临时对象gs,实现A的父类get/set和A的get/set的合并;

利用临时对象gs的当前内容对约定变量__gs进行更新,更新后的__gs用于给A的子类提供调用,如果A不存在子类,则该步骤不产生实际作用;

然后利用ES5内置的对象属性定义方法中的Object.defineProperties方法将临时对象gs定义到DOM对象div上,Object.defineProperties方法传入的2个参数分别为:DOM对象名称、临时变量名称。最终返回值为定义后的DOM对象。本步骤与上一步骤的执行次序可以交换。

在实际的代码转译过程中,由于很难了解到待转译代码中的类是否涉及继承:包括是否存在子类或父类,因此一般建议直接使用考虑继承的转译方案。

以上方案,是针对IE8等没有对普通JavaScript对象实现原生get/set方法的浏览器提出,使得转译后的get/set ES5代码可以在这些浏览中正确运行。在本申请的一种优选实施方式中,可以在转译过程中,为转译后的代码设置触发机制,以便在适当的时机使用本申请所提供的方法将get/set的ES6代码转译为“利用DOM实现get/set的代码”。

具体而言,可以在转译结果中,添加转译触发代码,该转译触发代码用于执行以下操作:

判断浏览器版本是否满足预设要求;

如果浏览器版本不满足预设要求,则触发执行所述功能代码。

基于前述实施例,添加转译代码后的转译结果如下:

上述代码中,增加了if判断触发语句,其中判定条件“浏览器版本不满足预设要求”为伪代码。增加判断触发的实际目的是:判断当前使用的浏览器版本是否对普通JavaScript对象实现原生get/set方法,即是否支持现有技术中的get/set直译结果,如果不支持,则触发向“利用DOM实现get/set的代码”的转译操作。

对浏览器版本的判断,可以采用获取浏览器版本信息、然后与预设的满足要求版本信息/不满足要求版本信息进行匹配得到。除该方法之外,本申请还提 供一种判断方法如下:

判断字符串+'\v1'的布尔值,若为true则满足预设要求,若为false则不满足预设要求。

该方法利用了不同浏览器对其实就是利用各浏览器对转义字符\v的理解:

在IE9以及其他较新版本的浏览器中,\v表示一个垂直制表符,相当于空格,所以对\v1解析结果为1,前面加上一个"+"是为了把后面的字符串转变成数字,因此整个字符串+'\v1'的解析结果为1,对应的布尔值将返回true;

而在IE8等早期浏览器版本中,\v没有转义,得到的结果为v,对\v1解析结果为v1;前面的"+"无法正确转变成数字,因此整个字符串+'\v1'的解析结果的布尔值将返回false。

根据上述分析,可以直接将伪代码“if(浏览器版本不满足预设要求)”用“if(!+'\v1')”来实现。

进一步地,还可以在转译结果中,添加get/set方法直译代码,即直接利用Object.defineProperty方法将get/set方法的声明名称、声明内容定义到所述get/set方法所属类的原型对象上的实现代码;并且在转译结果中增加直译操作的触发代码,用于在浏览器版本满足预设要求的情况下,触发执行get/set方法直译代码。

综上所述,一个get方法最终的转译结果代码示意如下:

也就是说,在一个set/get方法代码的转译结果中,包括两部分代码:

1)仅新版本浏览器能够正确运行的代码部分(直译代码);

2)早期版本浏览器能够正确运行的代码部分(利用DOM实现get/set的代码)。

两部分代码的实际功能是一致的,利用转译结果中的条件触发代码,使得该转译结果代码实际在浏览器中被执行时,能够自动根据浏览器版本判断选择实际需要触发哪部分代码运行。

可以理解的是,本申请中所涉及的转译结果代码仅用于示意性说明,其中例如变量名称、对象名称、以及具体的语法使用细节等均不构成对本申请方案的限制。另外,以上实施例中着重对get方法的ES6到ES5代码转译进行说明,set方法的ES6到ES5代码转译与get方法基本一致,本领域技术人员可以根据本申请实施例类推得到,在本申请中不再赘述。

相应于上述方法实施例,本申请还提供一种JavaScript代码转译装置,参见图4所示,该装置可以包括:

解析模块110,用于对待转译的ES6代码段进行解析,根据解析结果,确定待转译代码段中的get/set方法声明代码部分

类声明转译模块120,用于将get/set方法所属类的class声明代码转译为function声明代码;

get/set声明转译模块130,用于将get/set方法的声明代码转译为用于执行以下操作的功能代码:

创建一DOM对象;

将“this”关键字所指向对象的属性复制到DOM对象上;

利用ES5的对象属性定义方法,将get/set方法定义到DOM对象上;

以DOM对象作为返回值。

在本申请的一种具体实施方式中,上述装置还包括转译触发代码添加模块(图中未示出),用于在转译结果中,添加转译触发代码,转译触发代码用于执行以下操作:

判断浏览器版本是否满足预设要求;

如果浏览器版本不满足预设要求,则触发执行功能代码。

在本申请的一种具体实施方式中,上述装置还包括get/set声明直译模块(图中未示出),用于在转译结果中,添加get/set方法直译代码;

get/set方法直译代码用于执行以下操作:

利用Object.defineProperty方法将get/set方法的声明名称、声明内容定义到get/set方法所属类的原型对象上;

转译触发代码,还用于执行以下操作:

如果浏览器版本满足预设要求,则触发执行get/set方法直译代码。

上述装置中各个模块的功能和作用的实现过程具体详见上述方法中对应步骤的实现过程,在此不再赘述。

通过以上的实施方式的描述可知,本领域的技术人员可以清楚地了解到本申请可借助软件加必需的通用硬件平台的方式来实现。基于这样的理解,本申请的技术方案本质上或者说对现有技术做出贡献的部分可以以软件产品的形式体现出来,该计算机软件产品可以存储在存储介质中,如ROM/RAM、磁碟、光盘等,包括若干指令用以使得一台计算机设备(可以是个人计算机,服务器,或者网络设备等)执行本申请各个实施例或者实施例的某些部分所述的方法。

本说明书中的各个实施例均采用递进的方式描述,各个实施例之间相同相似的部分互相参见即可,每个实施例重点说明的都是与其他实施例的不同之处。尤其,对于装置实施例而言,由于其基本相似于方法实施例,所以描述得比较简单,相关之处参见方法实施例的部分说明即可。以上所描述的装置实施例仅仅是示意性的,其中所述作为分离部件说明的模块可以是或者也可以不是物理上分开的,在实施本申请方案时可以把各模块的功能在同一个或多个软件和/或 硬件中实现。也可以根据实际的需要选择其中的部分或者全部模块来实现本实施例方案的目的。本领域普通技术人员在不付出创造性劳动的情况下,即可以理解并实施。

以上所述仅是本申请的具体实施方式,应当指出,对于本技术领域的普通技术人员来说,在不脱离本申请原理的前提下,还可以做出若干改进和润饰,这些改进和润饰也应视为本申请的保护范围。

当前第1页1 2 3 
网友询问留言 已有0条留言
  • 还没有人留言评论。精彩留言会获得点赞!
1