見出し画像

Javascriptの歴史とバーション変化

はじめて

こんにちは、エアークローゼットでエンジニアをしているManhと申します。
この記事は、エアークローゼット Advent Calendar 2022 の11日目の記事です!よろしくお願いします!

JavaScriptの由来

JavaScriptは当初LiveScriptという名称で、Netscape Communicationsのブレンダン・アイク(Brendan Eich) 氏によって開発され、1995年12月にJavaScriptとして、Netscape Navigator 2.0で実装されました。
元々の目的はブラウザで表示する Webページ上で、フォームに入力した値をチェックしたり、時刻を表示したり、ゲームなどを実装することも可能となります。
なぜ、名称が変更したかというと、同年5月23日にSun Microsystems(のちのOracle Corporation)がJavaを発表しており、当時、Netscape CommunicationsとSun Microsystemsは提携関係にあったため、注目度の高かったJavaの勢いに便乗しようと改名しました。
Java と JavaScript は名前もよく似ていますし、いずれも C 言語を祖先として生まれた言語なので記述もよく似ていますが、まったく別物です。英語とドイツ語くらいの違いがあります

JavaScript のバージョン

ES5 の新機能

ストリクトモード(strict)

プログラミングのミスを見つけやすくします

ゲッター(getter)とセッター(setter)

var user = {
  _name: '',
  set name(name) {      // setter関数
    this._name = name;
  },
  get name() {          // getter関数
    return this._name;
  }
}
user.name = "Billy";   // => Set name : Billy
name = user.name;       // => Get name : Billy

オブジェクトの最後の属性の後ろにカンマ

var obj = {
  width: 160,
  height: 120,  // ES5 以降であればエラーとならない
};

JSON文字列の変換

var str = '{"width":160, "height":120}';
var obj = JSON.parse(str);
console.log(obj);  // {width: 160, height: 120}
---
function reviver(key, value) {
    return typeof value === 'number' ? value * 2 : value;
}
var str = '{"x": 123, "y": 234}';
var obj = JSON.parse(str, reviver);
console.log(obj);                    // => {x: 246, y: 468}

string.trim()

"   ABC   ".trim();        // => "ABC"

Object オブジェクトのメソッド強化

// Create object with an existing object as prototype
Object.create()

// Adding or changing an object property
Object.defineProperty(object, property, descriptor)

// Adding or changing object properties
Object.defineProperties(object, descriptors)

// Accessing Properties
Object.getOwnPropertyDescriptor(object, property)

// Returns all properties as an array
Object.getOwnPropertyNames(object)

// Accessing the prototype
Object.getPrototypeOf(object)

// Returns enumerable properties as an array
Object.keys(object)

// Prevents adding properties to an object
Object.preventExtensions(object)

// Returns true if properties can be added to an object
Object.isExtensible(object)

// Prevents changes of object properties (not values)
Object.seal(object)

// Returns true if object is sealed
Object.isSealed(object)

// Prevents any changes to an object
Object.freeze(object)

// Returns true if object is frozen
Object.isFrozen(object)

Array オブジェクトのメソッド強化

Array.isArray()
Array forEach()
Array map()
Array filter()
Array reduce()
Array reduceRight()
Array every()
Array some()
Array indexOf()
Array lastIndexOf()

ES5.1 の新機能

array.isArray()

console.log(Array.isArray("ABC"));           // false
console.log(Array.isArray(["A", "B", "C"]);  // true

ES2015(ES6) の新機能

クラス (class)

class Car {
  constructor(name, year) {
    this.name = name;
    this.year = year;
  }
}

テンプレート文字列 (`Hello ${name}`)

var name = "Billy";
var str = `ようこそ ${name} さん`;
console.log(str);  // ようこそ Billy さん

モジュール (import, export)

import message from "./message.js";
import { name, age } from "./person.js";

アロー関数 (=>)

// ES5
var x = function(x, y) {
   return x * y;
}

// ES6
const x = (x, y) => x * y;

デフォルト引数 (function(x=0, y=0))

function myFunction(x, y = 10) {
  // y is 10 if not passed or undefined
  return x + y;
}
myFunction(5); // will return 15

可変長引数 (function(x, y, ...arg))

function sum(...args) {
  let sum = 0;
  for (let arg of args) sum += arg;
  return sum;
}

let x = sum(4, 9, 16, 25, 29, 100, 66, 77);

定数 (const)

const a = 5;
a = 8;        // TypeError

局所変数 (let)

var x = 10;
// Here x is 10
{
  let x = 2;
  // Here x is 2
}
// Here x is 10

for of ループ (for item of items)

const cars = ["BMW", "Volvo", "Mini"];
let text = "";

for (let x of cars) {
  text += x + " ";
}

Map オブジェクト

const fruits = new Map([
["apples", 500],
["bananas", 300],
["oranges", 200]
]);
fruits.get("apples"); //500

Set オブジェクト

// Create a Set
const letters = new Set();

// Add some values to the Set
letters.add("a");
letters.add("b");
console.log(letters); // "a", "b"

配列関数 (from(), of())

var str = "ABC";
var arr1 = Array.from(str);
console.log(arr1);                  // => ["A", "B", "C"]

var set = new Set([123, "ABC"]);
var arr2 = Array.from(set);
console.log(arr2);                  // => [123, "ABC"]

var map = new Map([[1, 2], [2, 4], [4, 8]]);
var arr3 = Array.from(map);
console.log(arr3);                  // => [[1, 2], [2, 4], [4, 8]]

分割代入 ([x, y] = [10, 20])

[x, y] = [10, 20];    // x=10, y=20
[x, y, ...z] = [10, 20, 30, 40, 50];   // z=[30, 40, 50]

スプレッド構文 (...args)

var arr = ["Blue Green", "Red Yellow"];
console.log(arr.flatMap(x => x.split(" ")));  // => ["Blue", "Green", "Red", "Yellow"]

言語依存フォーマット (NumberFormat())

var ja = new Intl.NumberFormat("ja-JP");
console.log(ja.format(1234567.89));         // 1,234,567.89 (日本様式)

var en = new Intl.NumberFormat("en-US");
console.log(en.format(1234567.89));         // 1,234,567.89 (米国様式)

var de = new Intl.NumberFormat("de-DE");
console.log(de.format(1234567.89));         // 1.234.567,89 (ドイツ様式)

var jpy = new Intl.NumberFormat("ja-JP", { style: 'currency', currency: 'JPY' });
console.log(jpy.format(1234567.89));         // ¥1,234,567.89 (日本円)

非同期処理 (Promise)

const myPromise = new Promise(function(myResolve, myReject) {
// "Producing Code" (May take some time)

  myResolve(); // when successful
  myReject();  // when error
});

// "Consuming Code" (Must wait for a fulfilled Promise).
myPromise.then(
  function(value) { /* code if successful */ },
  function(error) { /* code if some error */ }
);
  • generator関数

function* generate() {
  yield 1;
  yield 2;
  return 3;
}
let generator = generate();
console.log(generator.next()); //  Object { "value": 1, "done": false }
console.log(generator.next()); // Object { "value": 2, "done": false }

ES2016(ES7) の新機能

array.includes()

var arr = ["Red", "Green", "Blue"];

if (arr.indexOf("Green") != -1) {
   ...
}     // 古い書き方
if (arr.includes("Green")) {
 ... 
}          // ES2016以降の新しい書き方

べき乗演算子(**)

let x = 5;
let z = x ** 3; // z = 5 * 5 * 5 = 125

ES2017(ES8) の新機能

オブジェクト参照 (object.values(), object.entries())

var obj = {x:100, y:200};
console.log(Object.values(obj));      // => [100, 200]

var obj = {x:100, y:200};
console.log(Object.entries(obj));     // => [["x",100], ["y":200]]

パディング (string.padStart(), string.padEnd())

let text1 = "5";
text = text1.padStart(5,"0"); // '00005'

let text2 = "5";
text = text2.padEnd(4,"0"); // '5000'

プロパティ記述子参照 (object.getOwnPropertyDescriptors())

var obj = { a: 100 };
var descs = Object.getOwnPropertyDescriptors(obj);
console.log(descs);    // => {a: {value: 100, writable: true, ...}}

関数末尾のカンマ (,)

function func(
  theFirstArgument,
  theSecondArgument,
  theThirdArgument,
) {
 ...
}
ret = func(a, b, c,); //引数の最後にカンマ(,)を記述することが許容されました。

非同期処理(async, await)

async function myDisplay() {
  let myPromise = new Promise(function(myResolve, myReject) {
    setTimeout(function() { myResolve("I love You !!"); }, 3000);
  });
  console.log(muyPromise); // I love You!!
}

myDisplay();

ES2018(ES9) の新機能

オブジェクトのスプレッド構文とレスト構文 (...obj)

var obj1 = {x: 200, y: 300};
var obj2 = {w: 400, h: 500};

var obj3 = {...obj1, ...obj2};              // スプレッド構文
console.log(obj3);                          // {x: 200, y: 300, w: 400, h: 500}

let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
x; // 1
y; // 2
z; // { a: 3, b: 4 }

正規表現のsフラグ (/.../s)

res = "12:34:56".match(/\d+/g);
console.log(res.length);     // => 3

res = "12:34:56".match(/\d+/);
console.log(res.length);     // => 1

"abc".match(/ABC/)     // マッチしない
"abc".match(/ABC/i)    // マッチする;

"123\n456\n789".match(/^456/)        // マッチしない
"123\n456\n789".match(/^456/m)       // マッチする

正規表現の名前付きキャプチャグループ (?<...>)

var str = "2019年12月31日";
var result = str.match(/(?<year>\d+)年(?<month>\d+)月(?<day>\d+)日/);
console.log(result.groups.year);      // 2019
console.log(result.groups.month);     // 12
console.log(result.groups.day);       // 31

Promiseのfinally構文

let myPromise = new Promise();

myPromise.then();
myPromise.catch();
myPromise.finally();

Promiseのfor await (... of ...)構文

async function for_await_of() {
    for await () {}
};

ES2019(ES10) の新機能

catch引数の不要化

try {
   :
} catch { //catch(e): ES2019(ES10) では、catch の引数を省略できるようになりました。
   :
}

Symbol.description

const sym1 = Symbol("foo");
console.log(sym1.description);     // => "foo"

JSON.stringify

let text = JSON.stringify("\u26D4"); // ⛔

function.toString() でコメントも文字列化

function add(x, y) {
    /* 加算 */
    return x + y;
}
console.log(add.toString());    // => function(x, y) { /* 加算 */ return x + y; }

Object.fromEntries()

const fruits = [
["apples", 300],
["pears", 900],
["bananas", 500]
];
const myObj = Object.fromEntries(fruits); //{apples: 300, pears: 900, bananas:500}

string.trimStart()と string.trimEnd()

"   ABC   ".trimStart();      // => "ABC   "
"   ABC   ".trimEnd();        // => "   ABC"

array.flat() と array.flatMap()

var arr = [[[1, 2], [3, 4]], [5, 6]];
console.log(arr.flat(2));              // => [1, 2, 3, 4, 5, 6]

var arr = ["Blue Green", "Red Yellow"];
console.log(arr.flatMap(x => x.split(" ")));  // => ["Blue", "Green", "Red", "Yellow"]

ES2020(ES11) の新機能

任意精度整数(BigInt)

通常の Number 型は 2^53 の精度を持ちますが、ES2020 で追加された 
BigInt を用いると任意精度の整数を扱うことが可能となります。
BigInt では整数の末尾に n を付加します。Number を BigInt 
に変換するには BigInt() を使用します。
console.log(123456789012345678901234567890n);	// 123456789012345678901234567890n
console.log(BigInt(12345));			// 12345n

for-in ループにおける順序保証

xx = [ "Blue", "Red", "Yellow" ];
for (i in xx) {
  console.log(xx[i]);
}

ヌル合体(Nullish Coalescing)演算子(??)

// 古い書き方(obj.fooが未設定の場合デフォルト値60を設定する)
if (typeof(obj.foo) == "undefined" || obj.foo == null) {
    obj.foo = 60;
}

// ES2020以降の新しい書き方
obj.foo = obj.foo ?? 60;

オプショナル連結(Optional Chaining)(?)

// これまでの書き方
if (response.body) {			// body が存在することを確認してから
  console.log(response.body.length);	// その属性にアクセスする
}

// ES2020以降の書き方
console.log(response.body?.length);	// => body が存在すれば length 値を、さもなくば undefined

string.matchAll()

for (var m of "2020-12-31".matchAll(/[0-9]+/g)) {
  console.log(m);
}
// => ["2020", index: 0, input: "2020-12-31", groups: undefined]
// => ["12", index: 5, input: "2020-12-31", groups: undefined]
// => ["31", index: 8, input: "2020-12-31", groups: undefined]

ダイナミックインポート(Dynamic Import)

import("./module.js").then(mod => {
   console.log(mod.a1);
});

export * as ns from module 構文

import * as mod from "./module.js";	// この2行を
export { mod };
   ↓
export * as mod from "./module.js";	// 1行で記述できる

Promise.allSettled()

p1 = Promise.resolve("OK1");
p2 = Promise.reject("NG2");
p3 = Promise.resolve("OK3");
Promise.allSettled([p1, p2, p3]).then(
   resolveList => resolveList.forEach(res => console.log(res)),
   rejectList  => rejectList.forEach(rej => console.log(rej))
);
// => {status: "fulfilled", value: "OK1"}
// => {status: "rejected", reason: "NG2"}
// => {status: "fulfilled", value: "OK3"}

ES2021(ES12) の新機能

論理代入演算子 (||=, &&=, ??=)

xx ||= 5;    // xx || (xx = 5); と同じ。xxが未設定など偽と判断される場合にxxに値を代入
xx &&= 5;    // xx && (xx = 5); と同じ。xxが設定済など真と判断される場合にxxに値を代入
xx ??= 5;    // xx ?? (xx = 5); と同じ。xxがnullかundefinedの時にxxに値を代入

let x = 100;
x &&= 5; // x = 5

let x;
x &&= 5; // undefined

let x = 10;
x ||= 5; // x = 5

let x;
x ||= 5; // 5

let x = 10;
x ??= 5; // 5

let x;
x ??= 5; // 5

string.replaceAll()

"AAA".replace("A", "X")		# => XAA
"AAA".replace(/A/g, "X")	# => XXX (全置換)
"AAA".replaceAll("A", "X")	# => XXX (全置換)

Promise.any()

function sample_race() {
    p1 = taskA();
    p2 = taskB();
    Promise.any([p1, p2]).then(() => {
        console.log("taskA or task B is finished.");
    });
}


弱参照(WeakRefs, WeakMap)

var obj = { name: "Billy", age: 26 };
var a1 = obj;			# 強参照
var a2 = new WeakRef(obj);	# 弱参照
   :
console.log(a1);		# { name: "Billy", age: 26 }
console.log(a2.deref());	# { name: "Billy", age: 26 } または undefined

let wmap = new WeakMap();
let obj = { "a": 1 };
wmap.set(obj, 1);
console.log(wmap.get(obj)); //1


最後に

最後までご覧いただきありがとうございました。
エアークローゼット Advent Calendar 2022はまだ続きますので、興味あれば、ぜひ他のエンジニア、PMの記事もご覧いただければと思います。


この記事が気に入ったらサポートをしてみませんか?