0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

JavaScriptの基礎概念、改めて言語化し直した記録

0
Posted at

きっかけ

JavaScriptはなんとなく書けてきた。でも「varletconst の違いをちゃんと説明してください」と聞かれたとき、即答できなかった。スプレッド構文も、動くコードは書けるが「なぜそう書くのか」の説明が曖昧だった。

使えることと理解していることは別だな、と改めて感じたので、自分なりに整理し直してみた。


JavaScriptとDOMの関係

まず前提として、JavaScriptはブラウザ上で動くプログラミング言語だ。ユーザーの操作に応じてページの表示を動的に変えられる。Node.jsを使えばサーバー側でも動く。

ただし、JavaScriptはHTMLを直接操作できない。ブラウザがHTMLを解析すると、その内容をツリー構造のオブジェクトとして構築する。これがDOMだ。JavaScriptはこのDOMを介して初めてHTMLにアクセスできる。

「JavaScriptでHTMLを操作する」という表現が一般的に使われるが、正確には「JavaScriptがDOMを通じてHTMLを操作する」という構造になっている。この区別は最初意識できていなかった。


var / let / const の使い分け

3つの違いを整理するとこうなる。

var let const
再宣言 可能 不可 不可
再代入 可能 可能 不可
スコープ 関数スコープ ブロックスコープ ブロックスコープ

var は関数スコープなので、if ブロックや for ループの中で宣言しても外から参照できてしまう。意図しない参照が起きやすく、現代のコードではほぼ使わない方向になっている。

基本的には const を使い、後から値を変える必要があるものだけ let を使う、という判断基準が実務では一般的だ。var を新規コードで書く理由はほぼない。


関数の書き方が複数ある理由

JavaScriptには関数の書き方が複数あって、最初は混乱した。

関数宣言

function greet(name) {
  return `Hello, ${name}`;
}

関数式(無名関数)

const greet = function(name) {
  return `Hello, ${name}`;
};

アロー関数

const greet = (name) => `Hello, ${name}`;

アロー関数は function キーワードを省略した短い記法だ。処理が1行に収まる場合は {}return も省略できる。

書き方の違いだけでなく、this の扱いに差がある点は別途整理が必要だと感じている(今回は深入りしない)。


コールバック関数の仕組みを整理した

「関数を引数として渡す」という書き方が最初ピンとこなかった。

function hello() {
  console.log('hello');
}

function execute(callback) {
  callback();
}

execute(hello);

execute(hello) と書いた時点では hello は実行されない。execute の中で callback() が呼ばれて初めて動く。「実行のタイミングを渡す側ではなく受け取る側に委ねる」という発想で、非同期処理や配列メソッド(forEachmap など)で頻繁に出てくる。


クラスとインスタンスの関係

クラスはオブジェクトの設計図で、インスタンスはそこから生成した実体、という整理は他の言語と変わらない。

class User {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

const user = new User('太郎', 20);
console.log(user.name); // 太郎

なぜインスタンスを生成するのかという部分も改めて整理した。複数の処理が同じオブジェクトを直接共有してしまうと、互いに干渉してしまう。インスタンスとして別のオブジェクトを生成することで、それぞれが独立したデータを持てる。

余談だが、ES6以前はクラス構文がなく、コンストラクタ関数で擬似的にクラスを表現していた。古いコードを読む機会があると function Person(name) { this.name = name; } のような書き方が出てくるが、これは現代の class に対応するものだと理解しておくと混乱しにくい。


スプレッド構文と参照の話

スプレッド構文は ... を使って配列やオブジェクトを展開する記法だ。

const a = [1, 2, 3];
const b = [...a, 4, 5, 6];
console.log(b); // [1, 2, 3, 4, 5, 6]

配列のコピーにも使える。

const a = [1, 2, 3];
const c = [...a];
c.push(4);
console.log(a); // [1, 2, 3]  ← 変わっていない
console.log(c); // [1, 2, 3, 4]

let c = a と書いてしまうと、ca の参照を持つだけなので、c を変更すると a も変わってしまう。スプレッド構文を使うことで、参照先とは独立した別の配列を作れる。

ただしこれは「シャローコピー(浅いコピー)」であることに注意が必要だ。ネストされたオブジェクトや配列の中身は参照がコピーされるだけなので、深い階層のデータは共有されたままになる。

[...a] でコピーした場合でも、ネストされた配列やオブジェクトはコピーされない。[{name: 'A'}] のような構造を扱うときは別の対処が必要になる。


整理して見えてきたこと

今回言語化できたのは、var/let/const の使い分けの根拠、関数の書き方の違い、コールバックの仕組み、スプレッド構文と参照の関係あたりだ。

まだ自分の理解が薄いと感じているのは、アロー関数と通常の関数における this の違いだ。「動きが変わるのは知っている」レベルで止まっていて、具体的にどういうケースで問題になるかを整理できていない。そこは次の課題にしたい。


この記事を書いた人について

株式会社Flexibilityでエンジニアをしています。
DX推進・システム開発を軸に、エンジニアが自律的に動ける環境を大事にしている会社です。

技術的に面白いことをやっていきたい方や、働き方に柔軟さを求めている方は、
よかったら一度のぞいてみてください。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?