かつてはJavaScriptという言葉が「ECMAScript標準」を指す、あるいは「独自実装を含んだ広義のJavaScript」を指し幅広い意味で使われていた。ゆえにどちらの意味でJavaScriptという言葉が使われているかは文脈で判断する必要があった[7]。たとえばかつてマイクロソフトによる実装はJScriptと呼ばれたが、JScriptをJavaScriptと呼ぶような場面があった。
ECMAScriptは仕様自体に独自の拡張を条件付きで認める記述があり[8]、ブラウザが実装しているスクリプト言語はすべてECMAScriptに準拠していることになる。広義の意味でこれをJavaScriptと呼ぶ場合、主要なブラウザが実装しているスクリプト言語はマイクロソフトやGoogle、Appleの実装も含めてJavaScriptである。
実装間での差異を吸収するためにPrototype JavaScript Frameworkなどのライブラリが用いられた。 市場のブラウザ間互換性がある程度確立された2000年ごろには、GoogleやAmazonなどのGAFAMもJavaScriptを積極的に利用し始めた。 また、JavaScriptはウェブブラウザの拡張機能を開発するための言語としても使われるようになった。当初は拡張機能用のAPIが統一されていなかったが、互換性を高めようとする動きがある[9]。 当初はインタプリタ方式で実行されることが一般的であったためJavaScriptの実行速度はさほど速くなかったが、現在ではJITコンパイルなどを利用した各種の最適化がなされており、各ウェブブラウザのベンダーともに高速化を図ってしのぎを削っている。さらには、この高速化を受ける形で、Node.jsのようにサーバサイドでもJavaScriptを使う動きが見られるようになった。 次世代のJavaScriptとして、"JavaScript 2.0" を作ろうとした動きは2度あったが、いずれもまとまらなかった。 1度目はECMAScript 3が完成したのち2000年から2003年にかけて発生したが、ネットスケープとマイクロソフトの対立でまとまらなかった。当時ネットスケープが提案していた案はアドビのActionScript 2.0に引き継がれ、マイクロソフトの案はJScript .NETへと引き継がれた。 その後もネットスケープ及びMozilla FoundationはECMAScriptの策定に並行してJavaScriptを拡張し、JavaScript 1.x系列としてバージョンアップを繰り返していた。ECMAScript側ではECMAScript 4の策定が1999年以降進められており[10]、2006年の時点でMozilla Foundationはこれに基づいてJavaScript 2.0を作成することを表明していた。MozillaはECMAScript 4の策定にあたって、Pythonの文法を一部取り込んだ案を提案しており、自身でもこれを実装していた[11]。 しかしその後、ECMAScriptの標準化作業がMozilla, Adobe, Opera, Googleらが推す ECMAScript 4 と、Microsoft, Yahoo! らが推す ECMAScript 3.1 に事実上分裂してしまった影響から、2008年8月に大きな方針転換があり、ECMAScript 4は破棄され後者がECMAScript 5として2009年に標準化された。ECMAScript 4に入る予定だった機能は新たに発足した「ECMAScript Harmony」に先送りとなった[12]。これは後にECMAScript 2015として標準化が完了した。 なお、ECMAScript 5が標準化されて以降、MozillaのJavaScript実装はECMAScriptへの準拠を謳うようになった[13]。そしてバージョン番号での呼称は行われなくなり、JavaScript 2.0は事実上死語となった。 JavaScriptの変数は var[14], let[15]およびconst[16] キーワードを使用して宣言できる。let x; // 変数xの宣言。値が未指定のため、特殊な値である undefined が入った状態となる。let y = 2; // 変数yの宣言。同時に 2 が代入される。const z = 5; // 定数zの宣言。同時に 5 が代入される。定数であるため、書き換えることはできない。 JavaScriptは言語仕様にI/Oが組み込まれておらず、それらは実行環境により提供される。ECMAScript 5.1の仕様では以下のように言及されている。[17] この仕様の中では外部データの入力または計算結果の出力は供給しない。 しかし、ほとんどの実行環境はConsole Standard[18]で規定されている console オブジェクトを持っており[19]、そこにコンソール出力を行える。以下に最小のHello worldプログラムを示す。console.log("Hello World!"); 再帰関数は以下のように書ける。function factorial(n) { if (n == 0) { return 1; } return n * factorial(n - 1);} 無名関数(またはラムダ式)の構文とクロージャの例は以下である。// ECMAScript 5以前の記法var displayClosure = function() { let count = 0; // ECMAScript 2015以降で可能な記法 return ()=> { return ++count; };}var inc = displayClosure();inc(); // 1 が返るinc(); // 2 が返るinc(); // 3 が返る 可変長引数は以下のように記述する[20]。var sum = function(...args) { let x = 0; for (const v of args) { x += v; } return x;}sum(1, 2, 3); // 6 が返る 即時実行関数式 (IIFE) の例。関数を用いることで変数をクロージャに閉じ込めることができる。var v;v = 1;var getValue = (function(v) { return function() {return v;};})(v);v = 2;getValue(); // 1 が返る 以下のサンプルコードは、様々なJavaScriptの機能を示したものである。"use strict"; // strictモードの宣言/* 2つの数値の最小公倍数を求める */function LCMCalculator(x, y) { // コンストラクタ関数 const checkInt = (x)=> { // 入れ子の関数 if (x % 1 !== 0) { throw new TypeError(x + " is not an integer"); // 例外のスロー } return x; }; // 行末のセミコロンは省略可能な場合があるが、省略は推奨されない。 this.a = checkInt(x) this.b = checkInt(y);}// オブジェクトのプロトタイプはコンストラクタ関数の prototype プロパティに格納するLCMCalculator.prototype = { // オブジェクトリテラル constructor: LCMCalculator, // このようにプロトタイプを上書きする場合は、 // constructorプロパティにコンストラクタ関数名を再指定する gcd: function () { // 最大公約数を計算するメソッド // 「ユークリッドの互除法」アルゴリズムで計算 let a = Math.abs(this.a), b = Math.abs(this.b); if (a < b) { // 変数の入れ替え const t = b; b = a; a = t; } while (b !== 0) { const t = b; b = a % b; a = t; } // 最大公約数の計算は一度でよいため、自分自身を計算済みの結果を返すメソッドで再定義(上書き)する。 // (これにより LCMCalculator.prototype.gcd の代わりに this.gcd が呼ばれるようになる。 // ただし、計算後にプロパティ a や b が変更されてしまうと、結果は誤りとなる。) // なお 'gcd' === "gcd", this['gcd'] === this.gcd である。 this['gcd'] = function () { return a; }; return a; }, lcm : function () { // 最小公倍数を計算するメソッド // 変数名は、オブジェクトのプロパティと衝突しない。例)lcm は this.lcm とは異なる。 // 以下では、浮動小数の精度の問題を避けるために this.a * this.b としていない。 const lcm = this.a/this.gcd()*this.b; // 最小公倍数の計算も一度でよいため、自分自身を計算済みの結果を返すメソッドで再定義(上書き)する。 this.lcm = function () { return lcm; }; return lcm; }, toString: function () { // toStringはオブジェクトを文字列に変換するときに呼ばれるメソッド。 // テンプレート文字列により文字列中に値を埋め込むことができる。 return `LCMCalculator: a = ${this.a}, b = ${this.b}`; }};// 汎用の出力関数の定義。この実装はWebブラウザ上でのみ動作する。function output(x) { document.body.appendChild(document.createTextNode(x)); document.body.appendChild(document.createElement('br'));}// 無名関数はさまざまな書き方が可能[[25, 55], [21, 56], [22, 58], [28, 56]].map(([a, b])=> new LCMCalculator(a, b)) // 配列リテラル + マッピング関数.sort((a, b)=> a.lcm() - b.lcm()) // 指定した比較関数を用いたソート.forEach(obj=> { output(obj + ", gcd = " + obj.gcd() + ", lcm = " + obj.lcm());}); 上記コードをウェブブラウザ上で実行すると、以下の結果が表示される。LCMCalculator: a = 28, b = 56, gcd = 28, lcm = 56LCMCalculator: a = 21, b = 56, gcd = 7, lcm = 168LCMCalculator: a = 25, b = 55, gcd = 5, lcm = 275LCMCalculator: a = 22, b = 58, gcd = 2, lcm = 638 JavaScriptはコードの最上階層に属するグローバルオブジェクトを提供している。JavaScriptにおけるグローバルオブジェクトはglobalThisである[21]。 それぞれのJavaScript実行環境において様々なAPIが存在しており、JavaScriptからそれらを呼び出すことができる。 HTML要素をJavaScriptから操作するためのDOM API(例: document.querySelector)、HTTPリクエストを送信するFetch API、マルチスレッドを可能にするWorkerなどが定義されている。これらは言語仕様であるECMAScriptからは独立した各々の仕様書でAPIが定義され、ブラウザ実装がJavaScriptバインディングを提供することでJavaScriptからの呼び出しが可能になっている。 ファイルシステムにアクセスするためのfs API(モジュール)や実行プロセスと相互作用するprocess APIなどが定義されている。Webブラウザがもつ強いサンドボックス要件が緩和されている点がNode.js APIの特徴の1つである。 alternative JavaScript (altJS) はJavaScriptへトランスパイルされるプログラミング言語の総称である。 JavaScriptへ新たな機能を追加する方法の1つに、新しい言語を定義しそのコードをJavaScriptへ変換する方法がある。そのようなJavaScriptへトランスパイルされる言語はaltJSと総称される。altJSの例としてCoffeeScriptやTypeScript、PureScriptが挙げられる。altJSを用いることで、新たな演算子や記法を導入し効率の良いJavaScript開発を行うことができる。素のJavaScriptはaltJSと対比してVanilla JSとしばしば呼ばれる[22]。 例えばTypeScriptは型の導入を可能にする。JavaScriptは動的型付けである。静的コード解析でJavaScriptコードへの型検査は実行可能だが、コード上に型表記をおこなうことはできない。altJSの1つであるTypeScriptはJavaScriptへ型ノーテーションを導入しトランスパイル時に型検査をおこなうことで、型をもったJavaScriptを実現している。
発展
JavaScript 2.0
文法詳細は「JavaScriptの文法(英語版
基本的な文法
(… indeed, there are no provisions in this specification for input of external data or output of computed results.)
複雑な例
機能
グローバルオブジェクト
エコシステム
実行環境API
Webブラウザ
Node.js
altJS
Size:65 KB
出典: フリー百科事典『ウィキペディア(Wikipedia)』
担当:undef