这类日常的JavaScriptweb开发工具想要成为一个有吸引力的替代品,至少要满足以下三个要求:1.从用户的角度看,创建的网站和app使用工具和原生用JavaScript编写的应用程序在外观、页面加载时间、页面启动时间和持续速度方面应该没有区别。2、从开发者的角度,希望通过这些工具无缝接入其他JavaScript库,进行高效调试。3.从商业的角度来看,应该有大量的开发者愿意接受工具的专业培训,并在企业中使用。学习工具所花费的时间应该很好地转化为生产力,使用该工具创建的应用程序足以满足不断变化的需求。这种类型的转换工具要想成功,必须满足以上三个要求。编译器试图在这三个要求之间取得平衡。对于日常生产环境中使用的编译器,这些方面都不能忽略。就Transcrypt而言,所有三个要求在特定的Transcrypt设计决策中都发挥了决定性作用。要求1:网站和应用程序的外观与使用的底层JavaScript库直接相关。因此,要具有相同的外观和感觉,站点或应用程序必须正确使用相同的软件库。虽然快速的网络连接可能会隐藏差异,但即使对于在公共网络或托管主机上运行类似大小代码的移动设备,也能实现相同的页面加载时间。这使得不可能在每次加载新页面时都下载编译器、虚拟机或更大的运行时。只有在服务器端将代码静态预编译为JavaScript时,才能实现与使用原生JavaScript相同的页面启动时间。页面中所需的代码量越大,差异就越明显。要实现相同的持续速度,必须生成高效的JavaScript代码。鉴于JavaScript虚拟机针对常见编程模式进行了高度优化,生成的JavaScript应该类似于手写的JavaScript,而不是模拟堆栈机器或任何其他底层抽象。需求2:要实现对所有JavaScript库的无缝访问,Python和JavaScript必须使用一致的数据格式、一致的调用模型和一致的对象模型。一致的对象模型需要将JavaScript基于原型的单继承机制与Python基于多继承的机制相融合。应该注意的是,JavaScript最近添加的关键字“class”对于弥合这种根本差异的需要完全没有影响。为了高效调试,设置断点和逐步执行代码等操作必须在源代码级别完成。也就是说,源码图是非常有必要的。一旦遇到问题,您需要通过检查生成的JavaScript代码来找出原因。因此,生成的JavaScript应该与Python源代码同构。利用现有技术意味着源代码必须是纯Python,而不是语法有所改变的变体。一个健壮的实现是使用Python的本地解析器。同样,语义必须是Pythonic,这一要求会产生实际问题,需要引入编译器指令以保持运行时效率。需求三:为了保护企业对客户端Python代码的投资,工具需要持久化。一个持续可用的客户端Python编译器应该具有良好的一致性和出色的性能。如何保持两者的平衡是编译器设计中最关键的部分。Python连续三年成为最佳计算机科学入门课程的教学语言,这一地位足以确保训练有素的Python开发人员的持续可用性。我们能想到的每一个后端计算领域都用到了Python。如果浏览器端编程可以用Python实现,那么所有的Python开发者都可以进行浏览器端编程。这些开发人员设计了大型的、长时间运行的系统,而不是孤立的、短期运行的前端脚本代码。在生产力方面,Python在保持程序运行时性能的同时显着提高了输出,这已经得到从其他编程语言转向Python的开发人员的认可。对于那些关键的操作,比如数值处理和3D图形处理,它们使用的库已经被编译成本地机器代码,这就是Python可以保持运行时性能的原因。最后但并非最不重要的一点是,对不断变化的需求持开放态度意味着支持所有级别的模块化和灵活性。基于类的面向对象编程为此做出了很大贡献,提供了多重继承和复杂的包和模块机制。此外,开发人员可以在不更改现有代码的情况下通过使用命名参数和默认参数来更改调用签名。比较一致性和性能:语言收敛发挥作用一些Python构造与JavaScript构造非常相似,尤其是在转换为最新版本的JavaScript时。两种语言之间有明显的趋同。具体来说,越来越多的Python元素被融入到JavaScript中,例如:for...of...、类(以有限的形式)、模块、解构赋值和参数传播。因为JavaScript虚拟机有for...of...等高度优化的组件,将此类Python组件转换为最匹配的JavaScript组件是有好处的。这样,同构转换生成的JavaScript代码可以受益于目标语言的优化机制,也易于阅读和调试。虽然Transcrypt中的很多调试是通过sourcemaps在Python中一步一步进行的,而不是在JavaScript代码中进行的,但是该工具不应该隐藏底层技术,而应该揭示底层技术,让开发者能够充分了解“真相”事”。这是更可取的,因为如果使用编译器指令,则可以将本机JavaScript代码插入Python源代码中的任何位置。下面是一个使用多重继承的代码片段,显示了Python和Transcrpyt转换后的JavaScript代码之间的同构。原始Python代码为:转换后的JavaScript代码为:专注于同构转换转换的局限性存在于细微之处,有时两种语言的差异是棘手的。例如,“+”运算符在Python中可以用来连接列表,但如果在JavaScript中同构使用“+”运算符,不仅会把列表转换成字符串,还会把字符串粘在一起。当然,a+b可以转换为__add__(a,b),但由于a和b的类型在运行时不确定,这将导致函数调用和动态类型检查代码。再举一个例子说明如何解释“真实”。空列表的布尔值在JavaScript中为True(或true),但在Python中为False。为了在应用程序中全局处理这个问题,需要对每个if语句进行转换,因为在Python构造ifa:中无法确定a是布尔值还是列表或其他类型。所以ifa:必须转换为if(__istrue__(a))。如果在内循环中这样使用,它会再次导致性能不佳。在Transcrypt中,嵌入在代码中的编译指令(即pragma)用于编译本机控制此类工件。这允许使用标准数学符号编写矩阵计算,例如M4=(M1+M2)*M3,而不会为perimeter=2*pi*radius等语句产生任何额外开销。从句法上讲,pragma只是在编译时执行对__pragma__函数的调用,而不是在运行时。导入包含def__pragma__(directive,parameters):pass的存根模块允许此代码无需修改即可在CPython上运行。此外,pragma可以放在注释中。统一类型系统,同时避免命名冲突Transcrypt统一了Python和JavaScript的类型系统,而不是让它们彼此相邻并即时转换。数据转换需要一些时间,增加目标代码的大小和内存使用,增加垃圾收集的负担,并使Python代码和JavaScript库之间的交互难以处理。因此,Transcrypt的决定是拥抱JavaScript世界,而不是创造一个平行世界。下面提供了一个使用Plotly.js库的简单示例:可选的pragma语句,它允许字典键省略引号,只是为了方便。除此之外,该代码看起来与相应的JavaScript代码非常相似。您可以注意到代码如何使用列表推导式,这是JavaScript中仍然缺乏的功能。开发者无需关心Python字典的字面量是如何映射到JavaScript字面量对象的,在编写Python代码时可以使用Plotly.js文档。转换不会在幕后发生。在任何情况下,Transcrypt字典都是一个JavaScript对象。统一类型系统时会出现命名冲突。例如,Python和JavaScript字符串都有一个split()方法,但两者的语义却大不相同。类似的冲突情况还有很多,Python和JavaScript还在不断进化,以后还会有其他的冲突。为了解决这个问题,Transcrpyt支持别名的概念。在Python中使用
