このブログのコンセプトって○○なん、知ってた? 何それ気になる〜

【コーディング週間日報】6/27(日)〜 7/3(土)の学習

長きにわたって遊びすぎました(笑)

今週から再び、アウトプットを発信できるようにしていきます。

ということで…

たーやま

6/20(日)〜 6/26(土)に行ったことを記載しました。

目次

6/27(日)のアウトプット

ビルトインオブジェクト

JavaScript にあらかじめ定義されているオブジェクトのこと。Number, Array, Stringなど、さまざまなオブジェクトがあります。

ビルトインオブジェクトは window オブジェクト内にたくさん格納されているため、確認してみましょう。

アイキャッチの画像は、検証ツールの console で window を調べたときのものです。

たくさんあるように見えますが、あれでも一部です。ほかのオブジェクトもあるので、気になったら確認してみると面白いかも。

ラッパーオブジェクト

プリミティブ値を内包するオブジェクトのことを言います。プリミティブ値にあるラッパーオブジェクトを使うと、さまざまな操作を行うことができます。

const s = new String("miyakorder");
console.log(s); // miyakorder

s は文字列「miyakorder」として定義された String というラッパーオブジェクトになりました。

ここからメソッドを使用することもできます。

const s = new String("miyakorder");
console.log(s.toUpperCase); // MIYAKORDER
たーやま

ちなみに、わざわざ String って書かなくてもメソッドを使うことはできます。

Symbol

ES6から導入された関数。プロパティーの重複を避けるために、必ず一意の値を返します。

const elephant = Symbol();
let animal = elephant;
if (animal === elephant) {
    console.log("ゾウは動物です。")
} else {
    console.log("ゾウが動物とか今更すぎてワロタ。")
} // ゾウは動物です。

Symbol はコンストラクター関数のように、new 演算子を使いません。実行すると値は返ってきますが、一意なのかどうかがわかりませんよね。

const elephant = Symbol();
const lion = Symbol();
if (lion === elephant) {
    console.log("ゾウとライオンは同じ動物です。")
} else {
    console.log("ゾウとライオンは動物ではありますが、イコールではありません。")
} // ゾウとライオンは動物ではありますが、イコールではありません。

ということで、Symbol を作成してイコールをとるのかを調べたところ、上記の実行結果になりました。

elephant の Symbol と lion のSymbol は別物だということがわかります。

プロパティーとディスクリプター

オブジェクトを定義すると、プロパティーには値(value)がセットされますが、値以外にも設定されるものがあります。

他に設定されるのは下記3つです。

・configurable
・enumerable
・writable

value を含む4つの値を設定することで、プロパティーがとる挙動を調整できます。これら4つのことを、ディスクリプターと呼びます。

プロパティーの設定値をみていくと、こんな感じです。

value:値
configurable:設定変更可能性
enumerable:列挙可能性
writable:値の変更可能性

では、実際にプロパティーを作成してみてみましょう。

const v = { aqua: 8 };
const descriptor = Object.getOwnPropertyDescriptor(v, 'aqua');
console.log(descriptor);

実行結果は次の画像のようになります。

この場合は、configurableenumerablewritable の3つが true を返し、value は 8 を返しています。

オブジェクトリテラルでプロパティーを定義した場合は、全ての値が true で設定されていることがわかります。

6/28(月)のアウトプット

getter / setter と static

getter / setter

ディスクリプターでは、value、configurable、enumerable、writable の4つがあることは前回でせつめいしました。

その他に2つ設定できるものがあります。それらが getset です。

get と set はあくまでオプション機能になるので、設定されない場合は undefined になります。設定すると、特別な機能をもたらすことができます。

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

Object.defineProperty(Person1.prototype, 'name', {
	get: function () {
		return this._name;
	},
	set: function (val) {
		this._name = val;
	}
});

const p1 = new Person1('Bob', 23);
console.log(p1.name)

ディスクリプターで設定される get と set が、getter / setter です。

static

クラス内で使用できる静的なメソッドを定義する場合に使うものです。

class Person2 {
    constructor(name, age) {
        this._name = name;
        this._age = age;
    }

    get name() {
        return this._name;
    }

    set name(val) {
        this._name = val;
    }

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

Person2.hello() // hello

hello の部分が静的メソッドです。静的メソッドは、インスタンス化せずに使用できます。

しかしオブジェクトの生成が行われていないため、this は使うことができません。

チェーンメソッド

個人的にわかりやすいなと思う例えが…。

jQuery の連結して記述するアレ

です。

$("method").css("font-size: 2rem;").text(ほげほげ捕鯨).alert("アラートです。");

私の場合はこれでイメージできました。それでは JavaScript ではどうするのかを記しておきます。

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

	hello(person) {
		console.log(`${this.name} says hello ${person.name}`);
		return this;
	}

	introduce() {
		console.log(`Hi, I'm ${this.name}, ${this.age} years old.`);
		return this;
	}

	shakeHands(person) {
		console.log(`${this.name} shake hands with ${person.name}.`);
		return this;
	}

	bye(person) {
		console.log(`Goodbye, ${person.name}.`);
		return this;
	}
}

const bob = new Person('Bob', 23);
const tim = new Person('Tim', 33);

bob.hello(tim).introduce().shakeHands(tim).bye(tim); 

// Bob says hello Tim
// Hi, I'm Bob, 23 years old.
// Bob shake hands with Tim.
// Goodbye, Tim.

それぞれの関数に引数を取れるようにし、person のインスタンスを出力しています。そして bob と tim のインスタンスを作成して実行しました。

それぞれのメソッドの戻り値が Person のインスタンスである必要があるため、return this; をつけています。

たーやま

イメージとしては jQuery のメソッドチェーンやけど、記述となるとかなり変わってくるな。

6/29(火)のアウトプット

演算子

値をもとにして処理を行い、その結果を返す記号のことを指します。「=」や「+」など、さまざまあります。

たーやま

値のことを『オペランド』とも言うで。

簡単な式であれば、演算子の知識はなくても対応できるかもしれません。が、複雑な式では演算子の知識はマストです。

まずは簡単な演算子からみていきましょう。

a = 3 + 5

この場合、a = 8 になることは言うまでもありません。そして、処理がどうなっているかを知らなくてもわかるような式です。

ちなみにどういった処理をしているかというと、まず 3 + 5 をしてから a の値に 8 を代入しています。

このように、「演算子は結果の値を必ず返す」ということは知っておくべきことです。

また、演算子には優先順位があります。1 〜 21 の優先度があり、数字が大きいものほど先に処理されます。

たーやま

詳しくは以下の記事をみてください。

では、演算子の優先順位で結果が変わることをみていきましょう。

function func() {
    let a = 0;
    return a++;
}

console.log( func() ); // 0

+1 を行う前の値が返ってくるので、 a = 0 が呼び出されます。なので、実行結果は 0 になります。

function func() {
    let a = 0;
    return a++;
}

console.log( func() * 5 ); // 0

この場合は先ほどの関数に 5 をかけただけです。0 に何をかけても 0 のままなので、実行結果は 0 になります。

function func() {
    let a = 0;
    return a++;
}

console.log( !func() * 5 ); // 5

not 演算子をつけると、実行結果は 5 になります。

たーやま

え、おもろ。

ってなりました(笑)

これは func() の結果が 0 になるため、not 演算子は true の値に変更します。オペランドの型が違う場合、暗黙の型変換が行われます。

同じ型にあわせて計算されるため、true の値を 1 に変換。

not 演算子の値は掛け算(乗算)よりも優先度が高いため、 1 * 5 の式になり、5 を返しています。

function func() {
    let a = 0;
    return a++;
}

console.log( ! ( func() * 5 ) ); // true

この場合は、()内を先に計算します。0 * 5 = 0 で false がきたものとして、not 演算子は true を返します。

なので、実行結果は true になります。

このように演算子によって実行結果が変わってくるので、理解しておく必要があります。

7/1(木)のアウトプット

ループ文とブロックスコープ

ループ文のブロックスコープは、1ループ毎にスコープが切り替わります。

for (let i = 0; i < 10; i++) {
    const j = i * 2;
    console.log(j);
} // 0, 2, 4, 6, 8, 10, 12, 14, 16, 18

const は再宣言も再代入もできません。なので、ループ文が1ループ毎に切り替わっていない場合は、エラーが起きるはずです。

しかしエラーは起こっていないので、ループ文は1ループ毎に切り替わっていることがわかります。

for (let i = 0; i < 10; i++) {
    const j = i * 2;
    setTimeout(function () {
        console.log(j); // 1秒後に 0, 2, 4, 6, 8, 10, 12, 14, 16, 18
    }, 1000)
}

setTimeout で1秒後に表示させるようにしました。ここに var を入れてみましょう。

for (let i = 0; i < 10; i++) {
    var j = i * 2;
    setTimeout(function () {
        console.log(j); // 18(が10回出力される)
    }, 1000)
}

var の場合は、ブロックスコープを取りません。なので、for 文外で宣言しているのと同じ意味になります。

setTimeout が実行されるころには、j はループが終わり切った18の値になっています。

だから18を10回分出力する結果になりました。

たーやま

スコープとかその辺にあったけど、const とか let はスコープをすり抜けるとかなかったはず。

7/2(金)のアウトプット

for…in と列挙可能性

列挙可能性は、ディスクリプターに含まれる enumerable のこと。true の場合は for…in で列挙されますが、false の場合はされません。

for…in のループでは、列挙可能プロパティに対して反復処理を実行します。

また、プロトタイプチェーンも列挙対象になるため、自分自身に設定されているプロパティのみ列挙したい場合は Object.hasOwnProperty() を使います。

Symbol については列挙の対象にはなりません。

一通り for…in についてみたところで、記述をしてみます。

const obj = {
	prop1: 'value1',
	prop2: 'value2',
	prop3: 'value3'
}

for (let key in obj) {
	console.log(key);
} // prop1 ~ prop3 だけ出力される

key を出力すると、プロパティが実行結果になりました。

const obj = {
	prop1: 'value1',
	prop2: 'value2',
	prop3: 'value3'
}

for (let key in obj) {
	console.log(key, obj[key]);
} // prop1 value1 ~ prop3 value3 が出力される

オブジェクトまで出力したい場合は、第二引数に obj[key] とすると出力されます。for…in の記述方法については以上です。

オブジェクトのプロトタイプについて、メソッドを追加したい場合を見てみましょう。

const obj = {
	prop1: 'value1',
	prop2: 'value2',
	prop3: 'value3'
}

Object.prototype.mtd = function() {}

for (let key in obj) {
	console.log(key, obj[key]);
}

console をみると、mtd の関数も追加されています。

ところで、オブジェクトのプロパティ自身にのみ列挙したい場合は、mtd の enumerable を変更する必要があります。

const obj = {
	prop1: 'value1',
	prop2: 'value2',
	prop3: 'value3'
}

Object.prototype.mtd = function () { }
Object.defineProperty(Object.prototype, 'mtd', {
	enumerable: false
});

let d = Object.getOwnPropertyDescriptor(Object.prototype, 'mtd');
console.log(d);

for (let key in obj) {
	console.log(key, obj[key]);
}

実行結果は以下の写真のようになります。

enumerable: false となっているため、Object.prototype.mtd = function () { } が列挙されていないことがわかりました。

7/3(土)のアウトプット

for…of と反復可能性

for…of を使うと、イテレーターを持つオブジェクトの反復操作を行うことができます。

イテレーターは、反復操作を行う際に使うオブジェクトのことで、Array, Map, argument などのオブジェクトを指します。

では使い方をみていきましょう。

const arry = ['a', 'b', 'c'];

for (let v of arry) {
    console.log(v);
} // a, b, c

v に渡ってくるのは配列の arry。なので、a, b, c が出力されました。for…of の基本的な書き方はこんな感じです。

for…of は配列が持っているイテレーターの挙動に従います。ということで arry のプロトタイプを見てみましょう。

すると、Symbol.iterator というものが出てきます。

for…of の実行時には、Symbol.iterator が使われます。なので、Symbol.iterator の値を書き換えることで for…of のループの挙動も変わります。

この記事が気に入ったら
いいね または フォローしてね!

よかったらシェアしてね!

この記事を書いた人

大阪出身26歳。宮古島の制作会社に勤めています。
コーディングとデザインにシバかれてます。

生き物や自然が好きやけど、特にクワガタムシが好き。
他、チャリとか釣りとか筋トレとかも好き。

目次
閉じる