先后呈现出了具备后端能力的node,具备移动开拓能力的reaC++t native,具备游戏渲染能力的cocos2d-js,以及iOS上的热修复技能JSPatch等等新技能。

咋一看,险些各个端都被JavaScript攻陷,大有一统江湖之势。

究竟,JavaScript如何做到上天入地无所不能?JavaScript真的能一统江湖吗?

html5listview模板早年端到全端JavaScript逆袭之路 Angular

浊世出英雄:JavaScript的出身故事要从JavaScript的由来提及。

高能瞎说淡版,正经脸的同学可以忽略

有人的地方就有江湖,有江湖的地方就有纷争。

故事要从当年的浏览器之战提及。

韶光回到1994年,

(→ 那时候我还是个宝宝~ #天真脸#)

景兄弟横空出世,并自带神器网景导航,战斗力爆表,势如劈竹,瞬韶光威震天下。

一出世就武装到牙齿,武力值这么高还自带兵器,这个科学吗?

港真,我也以为不科学,大概跟熊孩子哪吒、女男人雅典娜是一个品种吧?

这统统北方的老前辈微软大湿,都看在眼里,不甘天下尽归景兄弟这个初出茅庐的毛孩子,大湿积淀多年,潜心修炼一年,终于带着大杀器IE 1.0出关了,誓于景兄弟争个高低。

自此景兄弟的网景导航 VS 微软大湿的IE 的武备战役开始。

景兄弟仔细掂量,微软大湿财大气粗,内功深厚,臣妾实在是办不到啊啊啊啊啊啊。

景兄弟紧急调集门人切磋对策,有一门人曰:”以我们微薄之力硬磕,是切切使不得的。
如今我们,一是宜施行合纵之策,抱大腿,组成同盟!
二是避其锋芒,出奇招致胜。

于是景兄弟依照此策略,一方面找到了当时德高为重的另一位前辈SUN,组成了开拓者同盟。

(微软大湿:握草,同盟都粗来了,那我是不是得搞个部落?)

另一方面,景兄弟找到了铸造大师布兰登,请布大师帮忙升级兵器网景导航,大师便是大师,不费吹灰之力就完成了强化升级,然而布大师突发奇想,本来这是近间隔攻击兵器,假如有多一个远间隔攻击的能力那岂不是更好?Just do it. 想罢大师就加了一个远间隔攻击的feature。
于是有了自带远间隔攻击能力的网景导航2.0。
景兄弟一看这么流弊心里甚是欢畅,不过远间隔攻击的技能叫做LiveScript,觉得不是特殊Fashion。
特然想到这不是跟SUN前辈同盟嘛,SUN家的Java正是独霸武林之时。
不如把名字改成跟Java有关,蹭一把东风,蹭点光环。
一拍脑袋,JavaScript!


众门人一听:”好好好,JavaScript 流弊炫酷吊炸天!

果真第一节下半场,景兄弟携强化过的网景导航2.0 战个高兴,那是杠杠的!
人家一问,你咋还能远程攻击,你这个远程攻击用的是啥?答曰:JavaScript。
“JavaScript,一定是跟SUN家Java是一个系列产品,一定很流弊!
”#光环加成,各种膜拜脸#

微软大湿亏了一场,痛定思痛,也要搞远程攻击功能,果真不久,就祭出了同样带有远程攻击能力的IE 3.0,鉴于景兄弟的远程攻击叫做JavaScript,J开头的觉得该当比较流弊,以是微软大湿的叫做JScript。

然后战役就从地面贴身格斗战,开始逐步升级到了远间隔核战役。

正所谓,城门失落火,殃及池鱼。
这么打下去苦逼的是搬砖的页面仔,便是我这种,到处都是雷区,无处下脚。

末了到了1997年,“联合国安理会秘书长”艾玛(ECMA)出来调解,多方签署了“核不扩散条约”,约束各种远程攻击武器的利用,这才走上了正轨。

1995年SUN开拓了Java技能,这是第一个通用软件平台。
Java拥有跨平台、面向工具、泛型编程的特性,广泛运用于企业级Web运用开拓和移动运用开拓。
Java也伴随着互联网的迅猛发展而发展,逐渐成为主要的网络编程措辞。
名噪一时。

1994年Netscape公司成立,并推出了自己的浏览器的免费版本 Netscape Navigator,很快就霸占了浏览器市场。
到了 1995 年,微软公司开始加入,并很快发布了自己的 Internet Explorer 1.0。

1995年,当时在Netscape就职的Brendan Eich(布兰登·艾克),正为Netscape Navigator 2.0浏览器开拓的一门名为LiveScript的脚本措辞,后来Netscape与Sun Microsystems组成的开拓同盟,为了让这门措辞搭上Java这个编程措辞“热词”,将其临时改名为“JavaScript”,日后这成为大众对这门措辞有诸多误解的缘故原由之一。

JavaScript最初受Java启示而开始设计的,目的之一便是“看上去像Java”,因此语法上有类似之处,一些名称和命名规范也借自Java。
但JavaScript的紧张设计原则源自Self和Scheme。
JavaScript与Java名称上的近似,是当时Netscape为了营销考虑与SUN达成协议的结果。

==> 以是,JavaScript和Java实在没有半毛钱关系。

JavaScript推出后在浏览器上大得胜利,微软在不久后就为Internet Explorer 3.0浏览器推出了JScript,以与处于市场领导地位的Netscape产品同台竞争。
JScript也是一种JavaScript实现,这两个

JavaScript措辞版本在浏览器端共存意味着措辞标准化的缺失落,对这门措辞进行标准化被提上了日程,在1997年,由Netscape、SUN、微软、宝蓝等公司组织及个人组成的技能委员会在ECMA(欧洲打算机制造商协会)确定定义了一种名叫ECMAScript的新脚本措辞标准,规范名为ECMA-262。
JavaScript成为了ECMAScript的实现之一。
ECMA-262 第五版,即是ES5。

==> ECMA-262,包括ES5, ES6等是一个标准,JavaScript是ECMAScript的一个实现。

完全的JavaScript实现该当包含三个部分:

在网景导航2.0和IE 3.0涌现之后的几年间,网景和微软公司一直的发布新版本的浏览器,支持更多的新功能。
自此拉开了浏览器之战的序幕。
这场浏览器之战到现在还在连续,以下一张图看清楚过程。

从浏览器之战可以看出,各家浏览器比拼的大致两个方面视觉体验(渲染排版)和速率(脚本运行)。

==> 以是一个完全的浏览器组成,至少包含两个部分:

补充一个市情常见浏览器的内核和JavaScript引擎搭配:

其他JavaScript引擎,Rhino,由Mozilla基金会管理,开放源代码,完备以Java编写,可以看做SpiderMonkey的Java版。

把稳:webkit不单单只是一个排版引擎,webkit = 排版引擎 + JavaScript引擎。

==> 以是,JavaScript是动态措辞,它的运行都是基于JavaScript引擎,引擎大都是由静态措辞实现C++、Java、and so on。
JavaScript的能力也是由引擎授予。
不管是浏览器环境中是window,亦或是node环境中的process,均是由引擎供应。

(番外:Mozilla的人不知道为啥特殊喜好猴子,常常以猴子命名技能,以是看到带Monkey的,十有八九估计是他们搞的。

诺曼底上岸:JavaScript Binding/Bridge 桥接技能

在浏览器环境中,DOM、BOM、window工具、setTimeout/setInterval,alert,console等方法均不是JavaScript自身具备的能力,而是浏览器native实现,然后通过JavaScript引擎注入到JS运行的全局高下文中,供JS利用。

鉴别办法,在调试器console中打出来,带有[native code]的即是:

讲道理:

JavaScript运行 → 依赖于JavaScript引擎 ← 浏览器集成了JavaScript引擎,同时通过JavaScript引擎注入native代码工JS脚本利用

发散一下思维,只要有JavaScript引擎,就能运行JS脚本,不管有没有浏览器!
只是短缺浏览器供应的alert,window等方法。

既然浏览器可以往JavaScript引擎中注入代码,授予JS脚本在网页中分外的能力,同理我们可以自己集成JavaScript引擎,自己定义自己的方法往JavaScript引擎中注入,授予JS更多更强的自定义能力!

注入的关键是:值类型相互对应,Obj映射class的一个实例,function映射一个句柄或者引用

JavaScript数值型中的坑

JavaScript内部,所有数字都因此64位浮点数形式储存,纵然整数也是如此

这便是说,在JavaScript措辞的底层,根本没有整数,所有数字都是小数(64位浮点数)。
随意马虎造成稠浊的是,某些运算只有整数才能完成,此时JavaScript会自动把64位浮点数,转成32位整数,然后再进走运算。
由于浮点数不是精确的值,以是涉及小数的比较和运算要特殊小心。
只管即便避免利用JavaScript做精准打算和密集打算。

根据国际标准IEEE 754,JavaScript浮点数的64个二进制位,从最左边开始,是这样组成的。

第1位:符号位,0表示正数,1表示负数

第2位到第12位:储存指数部分

第13位到第64位:储存小数部分(即有效数字)

符号位决定了一个数的正负,指数部分决定了数值的大小,小数部分决定了数值的精度。

IEEE 754规定,有效数字第一位默认总是1,不保存在64位浮点数之中。
也便是说,有效数字总是1.xx…xx的形式,个中xx..xx的部分保存在64位浮点数之中,最长可能为52位。
因此,JavaScript供应的有效数字最长为53个二进制位(64位浮点的后52位+有效数字第一位的1)。

内部表现公式:(-1)^符号位 1.xx…xx 2^指数位

精度最多只能到53个二进制位,这意味着,绝对值小于2的53次方的整数,即-(253-1)到253-1,都可以精确表示。

而大部分的后端措辞,C++、Java、Python等的long型都是可以支持到64位,因此long型数据从后端措辞传给JavaScript会发生低位截断。
碰着这种情形一样平常利用String处理,如须要在JavaScript中做long型打算,须要自行实现打算器。

有了自行往JavaScript引擎中注入的想法,接下来便是剖析可行性。

大部分是JavaScript引擎是利用C++编写,如果自己的程序利用的是C++可以很方便的进行注入,如果是OC,可以利用OC和C++混编的形式。

其他措辞怎么破?

要在一门静态措辞上与动态措辞JavaScript相互调用,最便捷的办法是找到一个这门措辞实现的JavaScript引擎(开源),直接进行集成,注入。
如果没有,则须要利用多一层桥接,把这门措辞的接口暴露给C++,再由C++实现的JavaScript引擎将接口注入供JavaScript利用。

做事端集成思路&实践:

nodeJS中的桥接

我们都知道nodeJS,但是nodeJS的运行依赖于Google的V8 引擎,V8是C++实现,底层利用C++实现底层功能,比如网络,数据库IO,对外暴露一个布局器接口注入到高下文中,把稳此处暴露的只是一个布局器接口而不是一个创建完的实例。
然后实现了一个require的hook函数。
当利用require加载一个JS模块时,跟网页中利用AMD 的require并无异样,当利用require加载系统库,既是C++的模块时,会调用暴露出来的布局器接口,得到一个实例工具。
不管是装载JS模块还是装载C++模块,得到的都可以看做是一个Module Object,node会将装载完的模块缓存到binding_cache中,下次在别处的代码中利用require装载模块时,就会先去binding_cache中查找,如果找到了则返回该module object,如果没找到再实行上面的装载流程。

这便是node的基本事理:C++封装底层操作,通过V8注入,使得JS脚本有网络和IO能力

基于Spring的桥接

以上说到的几个都是C++层面的运用,那么经典的Java怎么玩?是不是Java就必须是静态措辞的玩法,没有办法像C++之类的,可以利用JS的动态特性?

当然不是。
这个时候,我们须要提及前面先容过的一个JS引擎 Rhino,Rhino是完备由Java编写,可想而知,Rhino险些便是为Java运用而生的。

用法是这样:

首先在我们的Java运用中集成Rhino;

所有的IO操作,网络操作等,都封装成service,并供应增编削查,setter && getter等多种方法

通过spring,把这些service bean注入到Rhino中;

把业务逻辑写到JS代码中,JS代码调用多个已注入的Java service处理业务逻辑,拼装数据返回!

好处:修正业务逻辑不须要修正Java代码,也便是不须要重新编译和支配,只须要刷新下跑在Rhino中的JS代码即可。
以往Java运用的一个痛点是支配,须要重新编译,打包,支配重启做事器,现在以这种形式开拓,可以达到做事真个热更新和热支配。
既可以享有Java做事的稳定性和可靠性,又可以享有JS的灵巧性。

这种技能和用法在差不多十年前就有过,前EMC的工程师基于EMC著名的商业产品Documentum,设计了一套Java开源的中小企业CMS系统Alfresco,在该系统中实现了这种技能,这种技能基于spring,叫做spring-surf,做了一个胶水层。
可以看做小十年前的node吧。

Demo,利用spring-surf框架的系统中一个webscript模块

categorynode.get.xml定义URL拦截器和权限掌握;

.get指明是处理GET要求,RESTful;

在categorynode.get.js中调用已注入的Java Bean处理业务逻辑;

若为网页要求返回.html.ftl,若为Ajax,返回.json.ftl;

(此处配套利用的是FreeMarker模板引擎)

==> categorynode.get.desc.xml

==> categorynode.get.js

==> categorynode.get.html.ftl

==> categorynode.get.json.ftl

移动端集成思路&实践:

React Native中的桥接

React Native目前也是非常火爆,RN程序的运行依赖于Facebook的RN框架。
在iOS、Android的仿照器或是真机上,React Native利用的是JavaScriptCore引擎,也便是Safari所利用的JavaScript引擎。
但是在iOS上JavaScriptCore并没有利用即时编译技能(JIT),由于在iOS中运用无权拥有可写可实行的内存页(因而无法动态天生代码),在安卓上,理论上是可以利用的。
JavaScriptCore引擎也是利用C++编写,在iOS和安卓中,JavaScriptCore都做了一层封装,可以无须关心引擎和系统桥接的那一层。
iOS/Android系统通过JavaScriptCore引擎将定制好的各种原生组件注入,如:listview,text等。

Cocos2d-JS中的桥接

cocos2dx是游戏开拓中非常常用的游戏渲染引擎,有一系列的产品,如:cocos2dx(C++),cocos2d-lua(lua), cocos2d-js(JavaScript)等多个产品。
个中最新退出的是cocos2dx的JS版本的cocos2d-js,编写游戏渲染殊效代码比较于C++和lua非常方便。
对付做须要常常更新的渲染场景,C++是静态措辞,每次修正都须要重新编译才能运行,显然是不得当的。
自然也就想到了脚本措辞,lua和js,两者有些类似,都是动态措辞,只须要集成一个运行引擎,供应一个运行的容器即可运行,同时通过引擎注入底层方法供脚本调用即可。
lua好处是精简,语法精简,引擎页很小很精简,以是不可避免的代码量会比js多,同时学习本钱比较高。
js的好处是有ECMAScrtpt的核心,语法比较丰富,同时有支持一些高等属性。
在cocos2d-js中,cocos2dx(C++)集成了SpiderMonkey(C++)作为JS运行引擎,中间做了一个胶水层既是JS Binding,通过引擎注入了一个cc的全局工具,映射的是底层C++的一个单例C++实例。
表面上写的是JS代码,实际上操作的是底层的C++。
cocos2d-js是代码可以运行在多种环境中,当运行的网页环境中时,利用的是cocos2d-html5引擎,底层操作的是canvas;当运行在客户端上时,利用的是cocos2dx引擎,底层操作的是C++,再由C++去操控openGL做绘制和渲染。
供应相同的API,对开拓者险些是透明无差异的,开拓者只须要关注实现效果即可。
达到一套代码,多端运行(网页端,客户端)。

JSPatch技能中的桥接

JSPatch是目前比较盛行的iOS上的热修复技能,JSPatch 能做到通过 JS 调用和改写 OC 方法最根本的缘故原由是 Objective-C 是动态措辞,OC 上所有方法的调用/类的天生都通过 Objective-C Runtime 在运行时进行,我们可以通过类名/方法名反射得到相应的类和方法。
JSPatch 的基本事理便是:JS 通报字符串给 OC,OC 通过 Runtime 接口调用和更换 OC 方法。

关键技能之一是 JS 和 OC 之间的互传。
JSPatch里包含了,一个JS引擎JavaScriptCore(Safari,React Native用的同款)。
用到了 JavaScriptCore 的接口,OC 端在启动 JSPatch 引擎时会创建一个 JSContext 实例,JSContext 是 JS 代码的实行环境,可以给 JSContext 添加方法,JS 就可以直接调用这个方法。
实质上便是通过JavaScriptCore引擎注入,暴露OC的方法供JS调用来实现动态修正OC的反射。

Demo,iOS热更新,热修复:

集成JavaScriptCore引擎;

通过引擎,桥接JS和OC;

通过JS修正OC反射。

详细的JSPatch技能先容请移步:https://github.com/bang590/JSPatch/wiki

关于JavaScript引擎:

在iOS 或 android 上能够运行的JavaScript 引擎有4个:JavaScriptCore,SpiderMonkey,V8,Rhino。
下面这个表格展示各个引擎在iOS 和 Android 的兼容性。

由于iOS平台不支持JIT即时编译,而V8只有JIT模式,以是V8无法在iOS平台利用(越狱设备除外,想体验iOS JIT的同学可以自行越狱)。

以是,目前可以做到横跨iOS和Android双平台的JS引擎,只有两款,即是SpiderMonkey和JavaScriptCore。

JavaScript引擎会受很多东西影响,比如交叉编译器的版本、引擎的版本和操作系统的种类等。

至于如何选择,可以参考:《Part I: How to Choose a JavaScript Engine for iOS and Android Development》

至此,JavaScript自在身于前端,到征战全真个逆袭之路,可以总结为“携引擎以令天下”。

不敷之处,还请各位看官轻拍~

参考文章:

bang590/JSPatch中问参考文档

Cocos2d-JS | Cocos2d-x官方参考文档

Alfresco官方参考文档

《Browser Wars: The End or Just the Beginning?》

《Part I: How to Choose a JavaScript Engine for iOS and Android Development》

《React Native 从入门到源码》