警惕Java,迎来JavaScript
![创建时间](/imgs/self/body/article/datetime_icon.gif)
![作者](/imgs/self/body/article/user_icon.gif)
最近Oracle控告搜索巨人Google,宣称其Android智能手机操作系统上的Dalvik虚拟机侵犯了Java专利,这很自然让很多的开发人员感到担心。但大多数分析指出,这场诉讼对绝大多数Java开发人员将不会有多少的影响,但有些程序员却惊恐不安,他们已经开始寻找一种可替代的语言了。如果你也是这样,你是否考虑过转向JavaScript?
“什么?”,你也许会诧异。任何一个开发人员或多说少都知道Java跟JavaScript几乎没有任何的关系。Netscape最初是想把这个跨浏览器的脚本语言叫做LiveScript,但Sun微系统公司说服他们使用JavaScript这个名字——他们的想法是要把JavaScript当成一种HTML和Sun的全功能的Java之间的桥梁。
但如果Sun漠视JavaScript的存在而认为Java将成为Web上的真正语言,那它就大错特错了。Java最终发现它的用武之地只是作为一种服务器端语言,JavaScript在浏览器里给了它致命打击。如今,像CommonJS和Node.js这样的项目把JavaScript扩展到了更广的地方,使它也能够扮演Java在数据中心上的传统角色。在这样一种神奇的角色转换中,JavaScript正在成为一种多才多艺的,强大的,功能齐全的Web语言,而Java却日益显现沦为昔日COBOL语言的结局。
桥接客户端/服务器端
估计经历了那个年代的人都能回忆起当时以浏览器为平台的Java applet的那种笨拙,丑陋,激不起兴趣的样子,它更多给人带来的是烦恼,而不是真正的用处。即使Sun最近的在富(rich)互联网应用技术的尝试 ——JavaFX,也没有使其在对抗其现有的竞争对手(包括Adobe Flash,微软Silverlight)的进程上前进多少。客户端Java,看起来在出生之日就已被判了死刑。
相似的,服务器端JavaScript(SSJS)也从来没制造出多少火花。早在1996年,Netscape Enterprise Server就支持SSJS,但它一种昂贵且有专利的产品。它很快就被开源的Apache server抢光了所有的市场,SSJS也随着它消失了。然而,在那些日子里,JavaScript的确成为了最适合Web页面的轻量级脚本语言。对比一下那个时期新兴的其它语言,例如Perl和 Python,JavaScript运行缓慢而且语法怪异,只有有限的功能支持。更糟糕的是,每个厂商对其的实现还各不相同,导致开发人员浪费时间写一些修改补丁和相关处理。
至今,JavaScript已经走了一段很长的路。独立的、开源的JavaScript引擎的出现——包括谷歌的V8,Mozilla的 SpiderMonkey,和WebKit的SquirrelFish Extreme——意味着任何人都可以在自己的代码里嵌入一个标准兼容的JavaScript解释器,无需你从头来开发它们。目前这三个项目正处在一场猛烈的性能竞赛中,每种引擎的性能都在稳定的进步。随着这些底层技术高速的成熟发展,JavaScript展现出了一种Java从未实现的态势:打破传统的领域壁垒,贯通服务器端和客户端。客户端的Java从未景气过,但服务器端JavaScript却杀了回来。.
服务器端JavaScript越来越受重视
现代的JavaScript引擎都能够单独的独立运行,这使得它们给SSJS提供了天然的便利。但目前JavaScript还只是主要的作为一种浏览器端的语言,这使得它缺少一些开发人员们期望的在其它环境中的功能特征。例如,客户端的开发人员通常是通过互联网加载单独的.js文件,而服务器端的开发人员需要一种更常用的方式,使代码程序能打成包。同样,JavaScript缺少常见的系统功能标准库,相比较而言,像C和Java这样的更加面向系统的语言在这方面要丰富的多。
CommonJS项目正试图解决这些问题。它的目标就是要创造出一套开放的、标准的API,提供诸如二进制对象处理,并行线程,文件、流、和套接字 I/O,系统日志处理等功能接口。除此之外,它还提议了一套代码和相关命名空间的模块格式标准。虽然这还是个很年轻的项目,但它的终极目标却是要让 JavaScript开发人员在写代码时有一个CommonJS规范,写出的程序在不作任何修改的情况下可以在任何CommonJS兼容的平台上运行——不论底层的JavaScript引擎和操作系统是什么。
然而,更令人兴奋的却是Node.js这个项目,它和CommonJS的初衷很相似,而且实现了一些CommonJS API。可是,它却把SSJS的概念提升到了一个新的高度。它的最重要的一项革新就是实现了针对服务器端开发的面向事件的编程模型。这意味着不仅仅 Nodo.js编程会让客户端的JavaScript开发人员感觉到得心应手——因为事件驱动模型是他们的开发规范,同时对于那些严重依赖于并行操作来支持多个并行用户的Web应用程序也是理想的选择。
如果这听起来像有一只手在向你招唤,请看看Node.js编程示例。这个完全等效的“Hello,world!”程序是只用了6行JavaScript代码的完全的HTTP服务器端实现。
JavaScript:Web之王?
不要奢望JavaScript能把Java从唯我独尊的宝座上拉下来。CommonJS和Node.js都还有很多的功课要做,一种精确的对这两个项目的描述应该是:试验品。对于更多的改进,例如特定的优化和管理工具等,就像Oracle对JRockit JVM所做的这方面的工作将会使Java成为企业软件开发的一个很有吸引力的平台。然而,JavaScript作为服务器端开发语言所带来的好处显而易见。它能够让Web开发人员用一种单一的语法实现所有的程序,去除了典型Web 应用上的混乱和混淆。JavaScript的运行效率的改进日新月异,这是开发人员最看重的。而JavaScript语言本身也发展成熟,成为一种不错的语言,具有同时支持面向对象和函数的编程风格的特征。
还有另外一点需要注意:JavaScript是完全免费和开放的,它由行业内厂商组成的ECMA标准委员会维护。ECMAScript工作组过去处于停滞状态,但它已经克服了种种困难,使JavaScript继续得到高速的发展。而同时,Java,一边假装开放,有不伦不类的JCP(Java Community Process)负责,一边又受到Oracle潜在的法律诉讼的威胁。如果Oracle自己不能意识的现在的形势,那我相信开发人员们可是清清楚楚的看清楚了。更多其相关信息可参考《Java发展轶事(202x)》。
上文源自:外刊IT评论
JavaScript 的三特点
1、作用域和闭包
作用域指代码当前上下文,控制着变量和函数的可见性和生命周期。最大的作用是隔离变量,不同作用域下同名变量不会冲突。作用域链指如果在当前作用域中没有查到值,就会向上级作用域查询,直到全局作用域,这样一个查找过程所形成的链条就被称之为作用域链。
作用域可以堆叠成层次结构,子作用域可以访问父作用域,反之则不行。作用域具体可细分为四种:全局作用域、模块作用域、函数作用域、块级作用域。
全局作用域:代码在程序的任何地方都能被访问,例如 window 对象。但全局变量会污染全局命名空间,容易引起命名冲突。
模块作用域:早期 js 语法中没有模块的定义,因为最初的脚本小而简单。后来随着脚本越来越复杂,就出现了模块化方案(AMD、CommonJS、UMD、ES6模块等)。通常一个模块就是一个文件或者一段脚本,而这个模块拥有自己独立的作用域。
函数作用域:顾名思义由函数创建的作用域。闭包就是在该作用域下产生,后面我们会单独介绍。
块级作用域:由于 js 变量提升存在变量覆盖、变量污染等设计缺陷,所以 ES6 引入了块级作用域关键字来解决这些问题。典型的案例就是 let 的 for 循环和 var 的 for 循环。
了解完作用域再来谈谈闭包:函数A里包含了函数B,而函数B使用了函数A的变量,那么函数B被称为闭包或者闭包就是能够读取函数A内部变量的函数。可以看出闭包是函数作用域下的产物,闭包会随着外层函数的执行而被同时创建,它是一个函数以及其捆绑的周边环境状态的引用的组合。换而言之,闭包是内层函数对外层函数变量的不释放。闭包的特征:
函数中存在函数;
内部函数可以访问外层函数的作用域;
参数和变量不会被 GC,始终驻留在内存中;
有内存地方才有闭包。
所以使用闭包会消耗内存、不正当使用会造成内存溢出的问题,在退出函数之前,需要将不使用的局部变量全部删除。如果不是某些特定需求,在函数中创建函数是不明智的,闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
2、原型和原型链
有对象的地方就有原型,每个对象都会在其内部初始化一个属性,就是prototype(原型),原型中存储共享的属性和方法。当我们访问一个对象的属性时,js引擎会先看当前对象中是否有这个属性,如果没有的就会查找他的prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。这么一个寻找的过程就形成了原型链的概念。
理解原型最关键的是理清楚__proto__、prototype、constructor三者的关系,我们先看看几个概念:
__proto__属性在所有对象中都存在,指向其构造函数的prototype对象;prototype对象只存在(构造)函数中,用于存储共享属性和方法;constructor属性只存在于(构造)函数的prototype中,指向(构造)函数本身。
一个对象或者构造函数中的隐式原型__proto__的属性值指向其构造函数的显式原型 prototype属性值,关系表示为:instance.__proto__ === instance.constructor.prototype
除了 Object,所有对象或构造函数的 prototype 均继承自 Object.prototype,原型链的顶层指向 null:Object.prototype.__proto__ === null
Object.prototype 中也有 constructor:Object.prototype.constructor === Object
构造函数创建的对象(Object、Function、Array、普通对象等)都是 Function 的实例,它们的 __proto__ 均指向 Function.prototype。
3、步和单线程
JavaScript 是单线程语言,意味着只有单独的一个调用栈,同一时间只能处理一个任务或一段代码。队列、堆、栈、事件循环构成了 js 的并发模型,事件循环是 JavaScript 的执行机制。为什么js是一门单线程语言呢?最初设计JS是用来在浏览器验证表单以及操控DOM元素,为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程。既然是单线程也就意味着不存在异步,只能自上而下执行,如果代码阻塞只能一直等下去,这样导致很差的用户体验,所以事件循环的出现让 js 拥有异步的能力。
Scala、Groovy、Clojure 、Kotlin 分别解决了 Java 的什么痛点
Scala、Groovy、Clojure、Kotlin这四种编程语言都旨在解决Java的某些痛点,包括繁琐的语法、静态性、并发编程复杂性、以及平台限制等。例如Scala提供了更简洁的语法和更强大的函数式编程能力,使得代码更加紧凑、表达力更强。Scala通过混合使用面向对象和函数式编程概念,提高了代码的抽象级别和可重用性,并且促进了并发编程。此外,Scala还能与Java无缝集成,充分利用现有的Java生态系统,这为希望保留Java生态优势同时解决其局限的开发者提供了便利。
1、Scala的功能强化
Scala是一种多范式编程语言,设计之初便致力于解决Java语言的一些核心痛点。首先,Scala在语法上比Java更加简洁,减少了冗余代码的编写,让开发者能够以更少的代码完成更多的工作。其次,Scala加入了强大的函数式编程特性,例如支持高阶函数、闭包、模式匹配等,这些特性使得构建复杂应用逻辑变得更加直观和高效。其还致力于解决并发编程难题,它引入了Actor模型和并发集合库,并与Java的并发工具兼容。这使得开发并发应用更加便捷,有助于处理现代计算机多核处理器的复杂性。
2、Groovy的简洁与灵活性
Groovy是一种动态语言,它在Java的基础上做了很多简化和增强。对于痛点的解决,Groovy的动态类型系统是一个明显的改进,允许开发者在不牺牲太多性能的情况下,享受更为灵活的编码体验。Groovy的脚本化特征也是对Java的一个补充,使其能够快速编写小的脚本和中间件代码,而不需要完整的Java应用框架。此外,Groovy还支持闭包和元编程等高级特性,为开发提供了极大的便利和强大功能。
3、Clojure的并发编程
Clojure是一种现代的、函数式的Lisp方言,它针对Java平台的并发编程提供了创新的解决方案。Clojure的核心特性包括其不可变数据结构和强大的并发编程支持。使用不可变数据结构,Clojure能有效避免多线程环境中的共享状态问题,这降低了并发编程的复杂性。另外,Clojure的软件事务内存(STM)系统为并发操作提供了一种更安全、更一致的方法来处理资源共享问题。
4、Kotlin的现代化语言特性
作为一种静态类型的编程语言,Kotlin是直接针对Java虚拟机(JVM)设计的,它在简洁性、安全性和互操作性方面解决了Java的许多问题。Kotlin的类型推断能力强,可以减少模板代码的编写,其空安全特性排除了NullPointerException这类错误的发生。Kotlin还支持函数式编程范式、协程,这些特性非常适合开发高并发的应用程序。此外,Kotlin与Java的高度互操作性保证了现有Java项目可以平滑地迁移到Kotlin,而不会失去对Java生态的支持。
综上,这些语言各自从不同角度对Java平台不同的痛点提供了解决方案,帮助开发者构建更高效、更可靠、更易于维护的软件系统。
相关问答FAQs:
为什么开发人员会选择使用Scala
Scala解决了Java中的一些挑战,例如更加简洁灵活的语法和强大的函数式编程特性。它还支持面向对象和函数式编程范式,使得代码更加简洁、易于维护。此外Scala还提供了更高级的类型系统和模式匹配功能,帮助开发人员减少错误并提高代码质量。
Groovy如何缓解了Java的一些痛点
Groovy通过引入动态类型和更加灵活的语法,降低了Java的一些繁琐性,简化了代码编写过程。它还提供了闭包、混合编程范式等功能,使得开发人员能够更快速地实现功能,减少重复代码的编写。此外,Groovy还具有与Java无缝集成的优势,可以轻松扩展已有Java项目。
Clojure是如何解决Java带来的挑战
Clojure作为一种函数式编程语言,通过强调数据不可变、简洁的语法以及并发编程的易用性来解决Java中的一些痛点。它提供了简洁的语法和强大的序列操作,帮助开发人员更加高效地处理数据集。Clojure还具有强大的并发处理能力,通过不可变数据结构来避免共享数据带来的问题,提高了程序的稳定性和可维护性。
JavaScript 诞生 25 周年纪
1995 年 12 月 4 日,Netscape 和 Sun Microsystems 宣布推出 JavaScript。在尝试制作动态网页时,Netscape 公司的 Brendan Eich 开始研究一种新的脚本语言。该语言的第一个版本在十天之内就被开发出来,并命名“Mocha”,之后更名为 LiveScript,最后改为 JavaScript。
1996 年 11 月,Netscape 开始对 JavaScript 进行标准化并向 ECMA International 提交提议。同年 12 月,W3C 提出 CSS1 规范。
1999 年 4 月 23 日,JSDoc 首次发布。10 月 13 日,ECMAScript 3 发布,新版本添加了规则表达式和 try/catch 异常处理,可以更好地处理错误,并且增加一些重要的增强功能。
2006 年 6 月 1 日,JSLint 推出,这是 JavaScript 语法检查器的始祖。
2006 年 1 月 14 日,JavaScript 库 jQuery 发布,它封装 JavaScript 常用的功能代码,提供一种简便的 JavaScript 设计模式,可以更轻松导航和操作 HTML DOM。
2009 年 11 月 8 日,Node.js 出现在公共视野。Node.js 是一个 JavaScript 运行环境,它让 JavaScript 可以开发后端程序,实现几乎其他后端语言实现的所有功能,这意味着 JavaScript 可以与 PHP、Java、Python、.NET、Ruby 等后端语言平起平坐。从那时起,“ 凡是能用 JavaScript 写的应用终将用 JavaScript 来写 ”开始在圈内广为流传。
2012 年 10 月 1 日,TypeScript 公开化。这是 Microsoft 推出的 JavaScript 的超集,最终会被编译为 JavaScript 代码。GitHub 刚刚发布的 2020 年度 Octoverse 报告显示,TypeScript 的受欢迎程度已成功超越 C#、PHP 和 C++,其排名从 2018 年和 2019 年的第七位上升到了今年的第四位。
2018 年 6 月 2 日,Node.js 创作者 Ryan Dahl 公开介绍了 JavaScript 和 TypeScript 的新运行时 Deno。Deno 是专门为了修复 Dahl 认为的 Node.js 的关键弱点而创建的--包括安全问题、使用集中式仓库系统(npm)以及"繁琐的工具"。
2020 年 5 月 13 日,Deno 1.0 发布,其创造者同样是 Node.js 的开发者 Ryan Dahl 。5 月 31 日,JavaScript 跟随 SpaceX Dragon 进入太空。Dragon 2 飞行界面使用 Chromium 和 JavaScript 搭建。
ECMAScript 2022 正式发布
ECMAScript 2022 现已于2022年6月下旬获得 ECMA International 的批准。ECMAScript 是标准化的 JavaScript 语言,于 1997 年发布了第一版,现已发展成为世界上使用最广泛的通用编程语言之一。本 Ecma 标准定义了 ECMAScript 2022 Language,是 ECMAScript 语言规范的第 13 版。主要包含内容有:
引入了 top-level await,允许在模块的顶层使用关键字;
新的 class elements:公共和私有实例字段、公共和私有静态字段、私有实例方法和访问器以及私有静态方法和访问器;
类内的静态块,用于执行每个类的评估初始化;
#x in obj语法,用于测试对象上是否存在私有字段;
class X {
#foo;
method() {
console.log(this.#foo)
}
}
通过/d flag 的正则表达式匹配索引,为匹配的子字符串提供开始和结束索引;
Error对象的cause属性,可用于记录错误的因果链;
Strings、Arrays 和 TypedArrays 的at方法,允许相对索引;
以及Object.hasOwn,这是Object.prototype.hasOwnProperty的一个更简洁方便的替代方法。
let hasOwnProperty = Object.prototype.hasOwnProperty
if (hasOwnProperty.call(object, "foo")) {
console.log("has property foo")
}
简化为:
if (Object.hasOwn(object, "foo")) {
console.log("has property foo")
}
具体可查看:
ECMA-262, 13th edition Language Specification
ECMA-262_13th_edition_Language Specification.pdf
众多JS社区成员联名让Oracle放弃JavaScript商标
javascript.tm网站上于2024年9月发起了一项让 Oracle 放弃 JavaScript 商标权的联名呼吁。目前已有包括 Node.js 的创造者、JavaScript 的创造者、Svelte 创始人、npm 创建者、Socket 首席执行官、JavaScript spec 编辑在内的 8000 多名 JS 社区成员署名!
![](/images/prodev/devsc/2017/moracle-js-trademark.jpg)
1995 年,Netscape 和 Sun Microsystems 合作开发了 JavaScript;2009 年,Oracle 收购了 Sun Microsystems,并因此获得了 JavaScript 商标。
这一封公开信敦促 Oracle 放弃对 JavaScript 商标的控制。文章指出,尽管 JavaScript 是世界上最流行的编程语言之一,但大多数人并不知道它是 Oracle 控制的商标。Oracle 持有 JavaScript 商标但不作为的行为符合商标放弃的法律定义,因为它已经连续三年未使用,且 JavaScript 已经成为一个通用名称,失去了作为商标的意义。Oracle 从未真正提供过名为 JavaScript 的产品,而且最近的商标使用示例并不反映其对商标的真正使用。
Oracle 的产品 GraalVM 和 JET 并不代表 JavaScript 的标准实现,而且 Oracle 并不是 OpenJS Foundation 的成员,也不参与 Node.js 的开发。JavaScript 的创造者 Brendan Eich 曾经表达过对 ECMAScript 名称的不满,ECMAScript 是 JavaScript 的标准规范名称。
文章还强调 JavaScript 社区组织因 Oracle 的商标控制权而被迫避免使用 JavaScript 名称的困境,其呼吁 Oracle 主动放弃商标权利,并说明如果 Oracle 不采取行动,将向美国专利商标局提出取消商标的请求。几个要点如下:
1、JavaScript 是一个广泛使用的编程语言,但其商标由 Oracle 控制,这种情况导致了广泛的混淆和卡壳。
2、Oracle 虽然持有 JavaScript 商标,但无具体作为,已经符合商标放弃的法律定义,因为它已经连续三年未使用,且 JavaScript 已经成为一个通用名称。
3、Oracle 从未真正提供过名为 JavaScript 的产品,其产品 GraalVM 和 JET 并不反映对 JavaScript 商标的真正使用。
4、JavaScript 的商标控制权导致了社区组织在命名和活动组织上的限制,如无法举办名为 “JavaScript Conference” 的活动。
5、JavaScript 的标准规范名称是 ECMAScript,而不是 JavaScript,这反映了 JavaScript 作为一个通用术语的现实。
6、联名授权页面可以发现,此次事件背后是 Deno 社区。
“什么?”,你也许会诧异。任何一个开发人员或多说少都知道Java跟JavaScript几乎没有任何的关系。Netscape最初是想把这个跨浏览器的脚本语言叫做LiveScript,但Sun微系统公司说服他们使用JavaScript这个名字——他们的想法是要把JavaScript当成一种HTML和Sun的全功能的Java之间的桥梁。
但如果Sun漠视JavaScript的存在而认为Java将成为Web上的真正语言,那它就大错特错了。Java最终发现它的用武之地只是作为一种服务器端语言,JavaScript在浏览器里给了它致命打击。如今,像CommonJS和Node.js这样的项目把JavaScript扩展到了更广的地方,使它也能够扮演Java在数据中心上的传统角色。在这样一种神奇的角色转换中,JavaScript正在成为一种多才多艺的,强大的,功能齐全的Web语言,而Java却日益显现沦为昔日COBOL语言的结局。
桥接客户端/服务器端
估计经历了那个年代的人都能回忆起当时以浏览器为平台的Java applet的那种笨拙,丑陋,激不起兴趣的样子,它更多给人带来的是烦恼,而不是真正的用处。即使Sun最近的在富(rich)互联网应用技术的尝试 ——JavaFX,也没有使其在对抗其现有的竞争对手(包括Adobe Flash,微软Silverlight)的进程上前进多少。客户端Java,看起来在出生之日就已被判了死刑。
相似的,服务器端JavaScript(SSJS)也从来没制造出多少火花。早在1996年,Netscape Enterprise Server就支持SSJS,但它一种昂贵且有专利的产品。它很快就被开源的Apache server抢光了所有的市场,SSJS也随着它消失了。然而,在那些日子里,JavaScript的确成为了最适合Web页面的轻量级脚本语言。对比一下那个时期新兴的其它语言,例如Perl和 Python,JavaScript运行缓慢而且语法怪异,只有有限的功能支持。更糟糕的是,每个厂商对其的实现还各不相同,导致开发人员浪费时间写一些修改补丁和相关处理。
至今,JavaScript已经走了一段很长的路。独立的、开源的JavaScript引擎的出现——包括谷歌的V8,Mozilla的 SpiderMonkey,和WebKit的SquirrelFish Extreme——意味着任何人都可以在自己的代码里嵌入一个标准兼容的JavaScript解释器,无需你从头来开发它们。目前这三个项目正处在一场猛烈的性能竞赛中,每种引擎的性能都在稳定的进步。随着这些底层技术高速的成熟发展,JavaScript展现出了一种Java从未实现的态势:打破传统的领域壁垒,贯通服务器端和客户端。客户端的Java从未景气过,但服务器端JavaScript却杀了回来。.
服务器端JavaScript越来越受重视
现代的JavaScript引擎都能够单独的独立运行,这使得它们给SSJS提供了天然的便利。但目前JavaScript还只是主要的作为一种浏览器端的语言,这使得它缺少一些开发人员们期望的在其它环境中的功能特征。例如,客户端的开发人员通常是通过互联网加载单独的.js文件,而服务器端的开发人员需要一种更常用的方式,使代码程序能打成包。同样,JavaScript缺少常见的系统功能标准库,相比较而言,像C和Java这样的更加面向系统的语言在这方面要丰富的多。
CommonJS项目正试图解决这些问题。它的目标就是要创造出一套开放的、标准的API,提供诸如二进制对象处理,并行线程,文件、流、和套接字 I/O,系统日志处理等功能接口。除此之外,它还提议了一套代码和相关命名空间的模块格式标准。虽然这还是个很年轻的项目,但它的终极目标却是要让 JavaScript开发人员在写代码时有一个CommonJS规范,写出的程序在不作任何修改的情况下可以在任何CommonJS兼容的平台上运行——不论底层的JavaScript引擎和操作系统是什么。
然而,更令人兴奋的却是Node.js这个项目,它和CommonJS的初衷很相似,而且实现了一些CommonJS API。可是,它却把SSJS的概念提升到了一个新的高度。它的最重要的一项革新就是实现了针对服务器端开发的面向事件的编程模型。这意味着不仅仅 Nodo.js编程会让客户端的JavaScript开发人员感觉到得心应手——因为事件驱动模型是他们的开发规范,同时对于那些严重依赖于并行操作来支持多个并行用户的Web应用程序也是理想的选择。
如果这听起来像有一只手在向你招唤,请看看Node.js编程示例。这个完全等效的“Hello,world!”程序是只用了6行JavaScript代码的完全的HTTP服务器端实现。
JavaScript:Web之王?
不要奢望JavaScript能把Java从唯我独尊的宝座上拉下来。CommonJS和Node.js都还有很多的功课要做,一种精确的对这两个项目的描述应该是:试验品。对于更多的改进,例如特定的优化和管理工具等,就像Oracle对JRockit JVM所做的这方面的工作将会使Java成为企业软件开发的一个很有吸引力的平台。然而,JavaScript作为服务器端开发语言所带来的好处显而易见。它能够让Web开发人员用一种单一的语法实现所有的程序,去除了典型Web 应用上的混乱和混淆。JavaScript的运行效率的改进日新月异,这是开发人员最看重的。而JavaScript语言本身也发展成熟,成为一种不错的语言,具有同时支持面向对象和函数的编程风格的特征。
还有另外一点需要注意:JavaScript是完全免费和开放的,它由行业内厂商组成的ECMA标准委员会维护。ECMAScript工作组过去处于停滞状态,但它已经克服了种种困难,使JavaScript继续得到高速的发展。而同时,Java,一边假装开放,有不伦不类的JCP(Java Community Process)负责,一边又受到Oracle潜在的法律诉讼的威胁。如果Oracle自己不能意识的现在的形势,那我相信开发人员们可是清清楚楚的看清楚了。更多其相关信息可参考《Java发展轶事(202x)》。
上文源自:外刊IT评论
JavaScript 的三特点
1、作用域和闭包
作用域指代码当前上下文,控制着变量和函数的可见性和生命周期。最大的作用是隔离变量,不同作用域下同名变量不会冲突。作用域链指如果在当前作用域中没有查到值,就会向上级作用域查询,直到全局作用域,这样一个查找过程所形成的链条就被称之为作用域链。
作用域可以堆叠成层次结构,子作用域可以访问父作用域,反之则不行。作用域具体可细分为四种:全局作用域、模块作用域、函数作用域、块级作用域。
全局作用域:代码在程序的任何地方都能被访问,例如 window 对象。但全局变量会污染全局命名空间,容易引起命名冲突。
模块作用域:早期 js 语法中没有模块的定义,因为最初的脚本小而简单。后来随着脚本越来越复杂,就出现了模块化方案(AMD、CommonJS、UMD、ES6模块等)。通常一个模块就是一个文件或者一段脚本,而这个模块拥有自己独立的作用域。
函数作用域:顾名思义由函数创建的作用域。闭包就是在该作用域下产生,后面我们会单独介绍。
块级作用域:由于 js 变量提升存在变量覆盖、变量污染等设计缺陷,所以 ES6 引入了块级作用域关键字来解决这些问题。典型的案例就是 let 的 for 循环和 var 的 for 循环。
了解完作用域再来谈谈闭包:函数A里包含了函数B,而函数B使用了函数A的变量,那么函数B被称为闭包或者闭包就是能够读取函数A内部变量的函数。可以看出闭包是函数作用域下的产物,闭包会随着外层函数的执行而被同时创建,它是一个函数以及其捆绑的周边环境状态的引用的组合。换而言之,闭包是内层函数对外层函数变量的不释放。闭包的特征:
函数中存在函数;
内部函数可以访问外层函数的作用域;
参数和变量不会被 GC,始终驻留在内存中;
有内存地方才有闭包。
所以使用闭包会消耗内存、不正当使用会造成内存溢出的问题,在退出函数之前,需要将不使用的局部变量全部删除。如果不是某些特定需求,在函数中创建函数是不明智的,闭包在处理速度和内存消耗方面对脚本性能具有负面影响。
2、原型和原型链
有对象的地方就有原型,每个对象都会在其内部初始化一个属性,就是prototype(原型),原型中存储共享的属性和方法。当我们访问一个对象的属性时,js引擎会先看当前对象中是否有这个属性,如果没有的就会查找他的prototype对象是否有这个属性,如此递推下去,一直检索到 Object 内建对象。这么一个寻找的过程就形成了原型链的概念。
理解原型最关键的是理清楚__proto__、prototype、constructor三者的关系,我们先看看几个概念:
__proto__属性在所有对象中都存在,指向其构造函数的prototype对象;prototype对象只存在(构造)函数中,用于存储共享属性和方法;constructor属性只存在于(构造)函数的prototype中,指向(构造)函数本身。
一个对象或者构造函数中的隐式原型__proto__的属性值指向其构造函数的显式原型 prototype属性值,关系表示为:instance.__proto__ === instance.constructor.prototype
除了 Object,所有对象或构造函数的 prototype 均继承自 Object.prototype,原型链的顶层指向 null:Object.prototype.__proto__ === null
Object.prototype 中也有 constructor:Object.prototype.constructor === Object
构造函数创建的对象(Object、Function、Array、普通对象等)都是 Function 的实例,它们的 __proto__ 均指向 Function.prototype。
3、步和单线程
JavaScript 是单线程语言,意味着只有单独的一个调用栈,同一时间只能处理一个任务或一段代码。队列、堆、栈、事件循环构成了 js 的并发模型,事件循环是 JavaScript 的执行机制。为什么js是一门单线程语言呢?最初设计JS是用来在浏览器验证表单以及操控DOM元素,为了避免同一时间对同一个DOM元素进行操作从而导致不可预知的问题,JavaScript从一诞生就是单线程。既然是单线程也就意味着不存在异步,只能自上而下执行,如果代码阻塞只能一直等下去,这样导致很差的用户体验,所以事件循环的出现让 js 拥有异步的能力。
Scala、Groovy、Clojure 、Kotlin 分别解决了 Java 的什么痛点
Scala、Groovy、Clojure、Kotlin这四种编程语言都旨在解决Java的某些痛点,包括繁琐的语法、静态性、并发编程复杂性、以及平台限制等。例如Scala提供了更简洁的语法和更强大的函数式编程能力,使得代码更加紧凑、表达力更强。Scala通过混合使用面向对象和函数式编程概念,提高了代码的抽象级别和可重用性,并且促进了并发编程。此外,Scala还能与Java无缝集成,充分利用现有的Java生态系统,这为希望保留Java生态优势同时解决其局限的开发者提供了便利。
1、Scala的功能强化
Scala是一种多范式编程语言,设计之初便致力于解决Java语言的一些核心痛点。首先,Scala在语法上比Java更加简洁,减少了冗余代码的编写,让开发者能够以更少的代码完成更多的工作。其次,Scala加入了强大的函数式编程特性,例如支持高阶函数、闭包、模式匹配等,这些特性使得构建复杂应用逻辑变得更加直观和高效。其还致力于解决并发编程难题,它引入了Actor模型和并发集合库,并与Java的并发工具兼容。这使得开发并发应用更加便捷,有助于处理现代计算机多核处理器的复杂性。
2、Groovy的简洁与灵活性
Groovy是一种动态语言,它在Java的基础上做了很多简化和增强。对于痛点的解决,Groovy的动态类型系统是一个明显的改进,允许开发者在不牺牲太多性能的情况下,享受更为灵活的编码体验。Groovy的脚本化特征也是对Java的一个补充,使其能够快速编写小的脚本和中间件代码,而不需要完整的Java应用框架。此外,Groovy还支持闭包和元编程等高级特性,为开发提供了极大的便利和强大功能。
3、Clojure的并发编程
Clojure是一种现代的、函数式的Lisp方言,它针对Java平台的并发编程提供了创新的解决方案。Clojure的核心特性包括其不可变数据结构和强大的并发编程支持。使用不可变数据结构,Clojure能有效避免多线程环境中的共享状态问题,这降低了并发编程的复杂性。另外,Clojure的软件事务内存(STM)系统为并发操作提供了一种更安全、更一致的方法来处理资源共享问题。
4、Kotlin的现代化语言特性
作为一种静态类型的编程语言,Kotlin是直接针对Java虚拟机(JVM)设计的,它在简洁性、安全性和互操作性方面解决了Java的许多问题。Kotlin的类型推断能力强,可以减少模板代码的编写,其空安全特性排除了NullPointerException这类错误的发生。Kotlin还支持函数式编程范式、协程,这些特性非常适合开发高并发的应用程序。此外,Kotlin与Java的高度互操作性保证了现有Java项目可以平滑地迁移到Kotlin,而不会失去对Java生态的支持。
综上,这些语言各自从不同角度对Java平台不同的痛点提供了解决方案,帮助开发者构建更高效、更可靠、更易于维护的软件系统。
相关问答FAQs:
为什么开发人员会选择使用Scala
Scala解决了Java中的一些挑战,例如更加简洁灵活的语法和强大的函数式编程特性。它还支持面向对象和函数式编程范式,使得代码更加简洁、易于维护。此外Scala还提供了更高级的类型系统和模式匹配功能,帮助开发人员减少错误并提高代码质量。
Groovy如何缓解了Java的一些痛点
Groovy通过引入动态类型和更加灵活的语法,降低了Java的一些繁琐性,简化了代码编写过程。它还提供了闭包、混合编程范式等功能,使得开发人员能够更快速地实现功能,减少重复代码的编写。此外,Groovy还具有与Java无缝集成的优势,可以轻松扩展已有Java项目。
Clojure是如何解决Java带来的挑战
Clojure作为一种函数式编程语言,通过强调数据不可变、简洁的语法以及并发编程的易用性来解决Java中的一些痛点。它提供了简洁的语法和强大的序列操作,帮助开发人员更加高效地处理数据集。Clojure还具有强大的并发处理能力,通过不可变数据结构来避免共享数据带来的问题,提高了程序的稳定性和可维护性。
JavaScript 诞生 25 周年纪
1995 年 12 月 4 日,Netscape 和 Sun Microsystems 宣布推出 JavaScript。在尝试制作动态网页时,Netscape 公司的 Brendan Eich 开始研究一种新的脚本语言。该语言的第一个版本在十天之内就被开发出来,并命名“Mocha”,之后更名为 LiveScript,最后改为 JavaScript。
1996 年 11 月,Netscape 开始对 JavaScript 进行标准化并向 ECMA International 提交提议。同年 12 月,W3C 提出 CSS1 规范。
1999 年 4 月 23 日,JSDoc 首次发布。10 月 13 日,ECMAScript 3 发布,新版本添加了规则表达式和 try/catch 异常处理,可以更好地处理错误,并且增加一些重要的增强功能。
2006 年 6 月 1 日,JSLint 推出,这是 JavaScript 语法检查器的始祖。
2006 年 1 月 14 日,JavaScript 库 jQuery 发布,它封装 JavaScript 常用的功能代码,提供一种简便的 JavaScript 设计模式,可以更轻松导航和操作 HTML DOM。
2009 年 11 月 8 日,Node.js 出现在公共视野。Node.js 是一个 JavaScript 运行环境,它让 JavaScript 可以开发后端程序,实现几乎其他后端语言实现的所有功能,这意味着 JavaScript 可以与 PHP、Java、Python、.NET、Ruby 等后端语言平起平坐。从那时起,“ 凡是能用 JavaScript 写的应用终将用 JavaScript 来写 ”开始在圈内广为流传。
2012 年 10 月 1 日,TypeScript 公开化。这是 Microsoft 推出的 JavaScript 的超集,最终会被编译为 JavaScript 代码。GitHub 刚刚发布的 2020 年度 Octoverse 报告显示,TypeScript 的受欢迎程度已成功超越 C#、PHP 和 C++,其排名从 2018 年和 2019 年的第七位上升到了今年的第四位。
2018 年 6 月 2 日,Node.js 创作者 Ryan Dahl 公开介绍了 JavaScript 和 TypeScript 的新运行时 Deno。Deno 是专门为了修复 Dahl 认为的 Node.js 的关键弱点而创建的--包括安全问题、使用集中式仓库系统(npm)以及"繁琐的工具"。
2020 年 5 月 13 日,Deno 1.0 发布,其创造者同样是 Node.js 的开发者 Ryan Dahl 。5 月 31 日,JavaScript 跟随 SpaceX Dragon 进入太空。Dragon 2 飞行界面使用 Chromium 和 JavaScript 搭建。
ECMAScript 2022 正式发布
ECMAScript 2022 现已于2022年6月下旬获得 ECMA International 的批准。ECMAScript 是标准化的 JavaScript 语言,于 1997 年发布了第一版,现已发展成为世界上使用最广泛的通用编程语言之一。本 Ecma 标准定义了 ECMAScript 2022 Language,是 ECMAScript 语言规范的第 13 版。主要包含内容有:
引入了 top-level await,允许在模块的顶层使用关键字;
新的 class elements:公共和私有实例字段、公共和私有静态字段、私有实例方法和访问器以及私有静态方法和访问器;
类内的静态块,用于执行每个类的评估初始化;
#x in obj语法,用于测试对象上是否存在私有字段;
class X {
#foo;
method() {
console.log(this.#foo)
}
}
通过/d flag 的正则表达式匹配索引,为匹配的子字符串提供开始和结束索引;
Error对象的cause属性,可用于记录错误的因果链;
Strings、Arrays 和 TypedArrays 的at方法,允许相对索引;
以及Object.hasOwn,这是Object.prototype.hasOwnProperty的一个更简洁方便的替代方法。
let hasOwnProperty = Object.prototype.hasOwnProperty
if (hasOwnProperty.call(object, "foo")) {
console.log("has property foo")
}
简化为:
if (Object.hasOwn(object, "foo")) {
console.log("has property foo")
}
具体可查看:
ECMA-262, 13th edition Language Specification
ECMA-262_13th_edition_Language Specification.pdf
众多JS社区成员联名让Oracle放弃JavaScript商标
javascript.tm网站上于2024年9月发起了一项让 Oracle 放弃 JavaScript 商标权的联名呼吁。目前已有包括 Node.js 的创造者、JavaScript 的创造者、Svelte 创始人、npm 创建者、Socket 首席执行官、JavaScript spec 编辑在内的 8000 多名 JS 社区成员署名!
![](/images/prodev/devsc/2017/moracle-js-trademark.jpg)
1995 年,Netscape 和 Sun Microsystems 合作开发了 JavaScript;2009 年,Oracle 收购了 Sun Microsystems,并因此获得了 JavaScript 商标。
这一封公开信敦促 Oracle 放弃对 JavaScript 商标的控制。文章指出,尽管 JavaScript 是世界上最流行的编程语言之一,但大多数人并不知道它是 Oracle 控制的商标。Oracle 持有 JavaScript 商标但不作为的行为符合商标放弃的法律定义,因为它已经连续三年未使用,且 JavaScript 已经成为一个通用名称,失去了作为商标的意义。Oracle 从未真正提供过名为 JavaScript 的产品,而且最近的商标使用示例并不反映其对商标的真正使用。
Oracle 的产品 GraalVM 和 JET 并不代表 JavaScript 的标准实现,而且 Oracle 并不是 OpenJS Foundation 的成员,也不参与 Node.js 的开发。JavaScript 的创造者 Brendan Eich 曾经表达过对 ECMAScript 名称的不满,ECMAScript 是 JavaScript 的标准规范名称。
文章还强调 JavaScript 社区组织因 Oracle 的商标控制权而被迫避免使用 JavaScript 名称的困境,其呼吁 Oracle 主动放弃商标权利,并说明如果 Oracle 不采取行动,将向美国专利商标局提出取消商标的请求。几个要点如下:
1、JavaScript 是一个广泛使用的编程语言,但其商标由 Oracle 控制,这种情况导致了广泛的混淆和卡壳。
2、Oracle 虽然持有 JavaScript 商标,但无具体作为,已经符合商标放弃的法律定义,因为它已经连续三年未使用,且 JavaScript 已经成为一个通用名称。
3、Oracle 从未真正提供过名为 JavaScript 的产品,其产品 GraalVM 和 JET 并不反映对 JavaScript 商标的真正使用。
4、JavaScript 的商标控制权导致了社区组织在命名和活动组织上的限制,如无法举办名为 “JavaScript Conference” 的活动。
5、JavaScript 的标准规范名称是 ECMAScript,而不是 JavaScript,这反映了 JavaScript 作为一个通用术语的现实。
6、联名授权页面可以发现,此次事件背后是 Deno 社区。