ブログ名

ながたかなです!

JavaScript 「再」入門 - JavaScript | MDN を読みます。

リンクです。

JavaScript 「再」入門 - JavaScript | MDN

いきなり本質パートですね。

大部分のプログラミング言語と違って、JavaScript という言語には入出力の概念がありません。この言語はあるホスト環境でのスクリプト言語として実行されるよう設計されており、外部の世界と...

概要

型は、数値、文字、関数、オブジェクト、Symbol(、undefined、null)のようです。さらにオブジェクトは関数、配列、Date、RegExp が特殊で、 Error などもあるようです。難しいですね。

数値

IEEE 754 の倍精度 64 ビットフォーマットのようです。誤差が出るので注意とありますが、これは C++ などでも同じですね。

0.1 + 0.2 == 0.30000000000000004;

このあたりもう少し詳しく知りたいものです。

実のところ、整数値は 32 ビット int 型として扱われます。また一部の実装では、32 ビット整数値ではなく Number で有効な命令の実行を求められるまでの間、32 ビット整数値として保存します。

Math というのはオブジェクトのようです。「標準ビルトインオブジェクト(複数形の、global objects)」というのに属するようですね。

Math.sin(3.5);

他のグローバルオブジェクトと異なり、Math はコンストラクタではありません。Math オブジェクトのすべてのプロパティとメソッドは、静的です。円周率を表す定数πは、Math.PI として参照でき、正弦関数は、 Math.sin(x) として呼び出すことができます (ここでの x は、メソッドの引数です)。

MDN で標準ビルトインを調べてみました。

Object, Function, Boolean, Error, EvalError, Number, Math, Date, String, RegExp, Array, Int8Array, Mpa, Set, WeakMap, Promise Generator, Reflect, WebAssembly...

このあたりの関数もそうみたいですね。

isNan(), parseInt(), ...

文字列

Unicode 文字(UTF-16)の列のようです。

プロパティ length、メソッド charAt(), `replace(), ... を持つようです。くわしくは 「 標準ビルトインオブジェクト > String 」までです。

その他の型

null: 値がない、undefined: 未初期化です。

true, false はキーワーッどのようです。

変数

このような違いがあります。

  • let: ブロック、可変
  • const: ブロック、不変
  • var: 関数、可変

演算子

これはなんですか?

'3' + 4 + 5;  // "345"
 3 + 4 + '5'; // "75"
123 == '123'; // true
1 == true; // true

比較演算に関しては、三重イコールが強いようです。

制御構造

for..of 構文というのがあるようですね。

for (let value of array) {
  // 値に関する処理
}

オブジェクト

なるほどです。

JavaScript のオブジェクトは、名前と値のペアの単純なコレクションであると考えることができます。

このあたり難しいです。function とありますが、これは関数とは違うのでしょうか。

以下の例ではオブジェクトのプロトタイプである Person と、プロトタイプのインスタンスである you を生成しています。

function Person(name, age) { this.name = name; this.age = age; }

// オブジェクトを定義する var you = new Person('You', 24); // "You" という名前で、年齢が 24 歳の新たな Person を作成しました

配列

なるほどです。length がとれるのが強いようですね。

JavaScript における配列は、実はオブジェクトの特殊型です。普通のオブジェクトとほとんど同じように働きます (数字のプロパティは当然 [] の構文でのみアクセスできます) が、しかし配列は 'length' という魔法のプロパティを持っています。

あの!?

array.length は必ずしも配列中の要素の数ではないことに注意してください。

イテレーションのやり方もいろいろあるようですね。for..of が ES2015 以降、forEach()ECMAScript 5 以降のようです。両バージョンの関係は何なのでしょう。

for (const currentValue of a) {
  // currentValue(現在の値)で何かをする
}
['dog', 'cat', 'hen'].forEach(function(currentValue, index, array) {
  // currentValue(現在の値) または array[index] について何かする
});

詳しくは「標準ビルトインオブジェクト > Array 」までです。

関数

これです! 私の知っている関数はこれです。さきほどの「プロトタイプ」というのはなんだったのでしょう。

function add(x, y) {
  var total = x + y;
  return total;
}

関数内では、arguments という変数を利用できます。詳しくは「関数 > arguments」 なのですが、ちょっと容量を得ずでした。this などの仲間と思うとよいのでしょうか……

また、「残余引数」...args というのがあり、こちらは Arrayインスタンスのようで、各種便利なメソッドが使えるようです。上位互換でしょうか。

このように、引数がたくさんある関数に、配列を渡すこともできるようです。便利ですね。

avg.apply(null, [2, 3, 4, 5]); // 3.5

さらに「スプレッド構文」というのもあるようです。実際には配列だけでなく、「反復可能」オブジェクト詳しくは「式と演算子 > スプレッド構文」

カスタムオブジェクト

これがクラスの代わりのようです。むーん、へんなかたち……

function makePerson(first, last) {
  return {
    first: first,
    last: last,
    fullName: function() {
      return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
      return this.last + ', ' + this.first;
    }
  };
}

this はドットの左に書いてあるオブジェクトのようです。ドットがないときにはグローバルのようです。 内部実装の this の意味がかわるの、かなりとらっぷですね。

s = makePerson('Simon', 'Willison');
var fullName = s.fullName;
fullName(); // undefined undefined

new キーワードはコンストラクタのようなもののようです。

function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = function() {
    return this.first + ' ' + this.last;
  };
  this.fullNameReversed = function() {
    return this.last + ', ' + this.first;
  };
}
var s = new Person('Simon', 'Willison');

そんなことをせずとも、このように「関数呼び出し」の記法でよくありませんか? と思い、Code Pen で試してみたのですが、このように TypeError となります。なるほどです。JavaScriptthis の呪いはコンストラクタにもあるのですね。new で回避できるというのがむしろ特殊ルールのようです。

var s = Person('Simon', 'Willison');
Uncaught TypeError: Cannot set property 'first' of undefined 
 at pen.js:3

MDN に行くと、とても腑に落ちるご説明がありました。なるほどです。まずは new をして、そのあとで関数呼び出し、といった意味なのですね。

new 演算子は、コンストラクター関数を持ったユーザー定義のオブジェクトまたは組込みオブジェクトのインスタンスを生成します。 new のキーワードは以> 下のことを行います。

1.空の JavaScript オブジェクトを生成する

  1. このオブジェクト (のコンストラクター) を他のオブジェクトへリンクする

  2. ステップ 1 で新しく生成されたオブジェクトを this コンテキストとして渡す

  3. 関数が自分自身を返さない場合は this を返す

さらに、こうすると person オブジェクトを作るたびにメソッドのために関数オブジェクトを作らなくてす済むようです。なるほどです。このあたり C++ ならば気にしなくて良いところだったのですが、そのようになっているのですね。しかしオブジェクトならば、C++ の変数のノリで考えると参照ではなくてコピーをすると思うのですが、JavaScript はシャローコピーベースなのでしょうか。

function personFullName() {
  return this.first + ' ' + this.last;
}
function personFullNameReversed() {
  return this.last + ', ' + this.first;
}
function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = personFullName;
  this.fullNameReversed = personFullNameReversed;
}

さらにこのようにかけるようです。

function Person(first, last) {
  this.first = first;
  this.last = last;
}
Person.prototype.fullName = function() {
  return this.first + ' ' + this.last;
};
Person.prototype.fullNameReversed = function() {
  return this.last + ', ' + this.first;
};

prototype ときくと泡を吹いて倒れるタイプの火星人なのですが、なるほどです。隠し機能が多すぎませんか!?

Person.prototype は Person のすべてのインスタンスで共有されるオブジェクトです。

名前解決の文脈で考えると良いようです。まずはオブジェクトのプロパティをチェックして、なければプロトタイプを見に行くようです。

また、これは途中でメソッドを増やしている感じなようで、Person.prototype.fullName = ... の前で呼び出しをしようとすると失敗します。

さらに組み込みオブジェクトにメソッドを増やすこともできるようです。恐ろしいですね。

apply のおともだちに call というのがあり、こちらは展開済みな引数をとるようです。

内部関数

関数の中に関数をかけます。

クロージャ

実行するたびに関数を生成するようです。

function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6); // ?
y(7); // ?