経緯
- 業務プロダクトをTSにする前に、JS力を高めようとなったので続き
感想
- JSはES5 だけでなく、ES2015-2017 で段階的に強化されたのだなあ (classはES5ではなかった)
構成
- 今回の章はES2015ではなく
ES5 だった
ES3 1999年
ECMAScript 5th Edition ES5 PDF 2009年12月
ECMAScript 2015 ES2015(別名ES6) PDF, HTML 2011年6月
11章は 9節まである
11章 ES5
十一章第一回 配列 (かなりnagai、31分)
array.lengthはarray["length"]としても参照可能 プロパティはこのような形でも三章可能 - 前にも説明あったと思う
プロパティ名に文字列以外が渡された場合は文字列に変換されます 数字から始まるプロパティ名の場合はarray.0のようにドットを使って参照することはできません
- push & pop
pushは、配列の最後に要素を追加 popは引数がなく、最後の要素を取り除きます。取り除いた要素は戻り値となります。
逆に、最初に要素を追加するメソッドもあります。それがunshiftです。一方、最初の要素を取り出すのがshiftです。
- hairetsu.splice(1,2) 2※から2つぬき出す
array.splice(1,1,"小沢一郎");
- 鳩山由紀夫が小沢一郎になる
- 4つ、5つとさらに入れるものをふやせる
- array.reverse();
- array.sort();
- 引数なしなら辞書順 (コードポイント順)
- 数値大照準ではない
0未満ならaのほうがbより小さい(aのほうがbより前)、0より大きいならaのほうがbより大きい(aのほうがbより後)、0なら同じ
return a-b; が簡単
array.sort(function(a,b){return a-b});
- 無名関数版
- .sort() も破壊的メソっょ
var newarray = array1.concat(array2);
- 配列を文字列にする .join()
- .slice() も非破壊的
- 引数はspliceと違って、 slice(開始位置, 終了位置)
- 終了位置の一つ前まで返す
- indexOf、ないときは-1
- 第2引数に探し始めるところがある (つかわなさそう)
- 後ろから探す lastIndexOf()
- ES5で登場した foreach
array.forEach(function(x){ var li=document.createElement("li"); li.textContent=x; ul.appendChild(li); });
- まぁ for とあまりかわらないかな?
主な利点は、カウンタ変数(for文を使ったさっきのサンプルの場合、変数i)がいらない
- 第2引数は現在の添字、第3引数は現在処理している配列そのもの
- mapは同じ引数が関数にくる。return すると、return した結果からなる配列を map が返す
- JSにはメソッドチェーンがあるよ 2021/11/23 21:05 25m
- .filter(function(){}) は、 funcが true (になるものを)返したものだけの配列を返すよ
every,some:配列の各要素に対する条件判定。。配列があって、「その中のどれか1つでも条件を満たせばok」とか「全て条件を満たせばok」という状況があります
someは、配列の要素の中でコールバック関数がtrueを返すものが1つでもあればtrueを返し、1つもなければfalseを返します
array.some(function(x){return x<=5;})
reduceです。これは関数型プログラミング言語の界隈ではfold(あるいはfold_left)と呼ばれています。
var sum=array.reduce(function(s,val){ return s+val; }, 0);
- 第1引数がそれまでの計算結果、第2引数が配列の要素
- 返り値はこの要素も含めた計算結果
- 逆からやる reduceRightもあります。
2021/11/23 21:11 読み終 31m
十一章第二回 bind
https://uhyohyo.net/javascript/11_2.html
bindは九章第五回でちらっと出てきたもので、ある関数が呼ばれたときのthisの値を固定するためのメソッドです。
- var foo = showThis.bind("菅直人");
- function showThis で this を固定した関数を作る
コールバック関数の中でも外側のthisの値を使いたい場合など、thisの値を保存したい場合には役に立ちます
bindはthisだけでなく引数も固定できます
var foo = sum.bind(null,10);
- this を null にして固定せず、最初の引数を固定してる
十一章第三回 console
https://uhyohyo.net/javascript/11_3.html
- console.logの仲間
consoleという変数に入ったオブジェクトが持つlogというメソッド
console.debug,console.info,console.warn,console.error
- これらは、 console.log の重要度が違う版、アイコンがかわったりする
- 大量にログ出すときは便利かもね
- console.dirは、「オブジェクトの場合はそのプロパティ一覧を表示する」というはとになってる
- conosle.log の強い版 プロパティ一覧が見やすいらしい
- console.assert 第一引数に条件、第二引数以降が今まで同様に表示するもの
- 条件true で何もコンソールにださない
falseなら、第二引数以降の内容を表示しつつエラーを発生させて停止します(九章第八回で紹介したthrowと同じ感じです)
console.trace。。これは引数なしで、コンソールに現時点でのコールスタックを表示します
console.groupは、コンソールに表示されるログをグループ化します
console.group自体にも引数を指定することで、通常どおりログに表示させることができます。。。console.groupが呼び出された後に続くログは、そのconsole.groupのログを親としてまとめられ(グループ化)、まとめて折りたたんだりできるようになります。このグループ化は、console.groupend(引数なし)が呼び出されるまで続きます。 ちなみに、groupCollapsedというのはgroupと同じですが、最初からそのグループが閉じてまとまった状態で表示されます。
profileが呼ばれてからprofileEndが呼ばれるまでの、実行時間などのデータを取得できます。ちなみにprofileには引数を指定することができ、あとで結果を表示するときにそのタイトルとなります - ◎便利そう console.profile
console.time?console.timeEndです。これは要するにタイマーで、timeが呼ばれてからtimeEndが呼ばれるまでの時間を測定します。測定結果は、timeendのときにコンソールに出力されます
console.countが呼ばれるたびに数字を1増やして出力します
2021/11/25 1:14 11-3 おわり 2021/11/25 1:14 17m
十一章第四回 Objectとプロパティ
https://uhyohyo.net/javascript/11_4.html
ES5の特徴は、オブジェクト、特にプロパティに対する操作が強化されたことです。
- オブジェクトリテラル
- var obj={ foo:"bar", baz:3, };
古典的な方法としてはfor-in文があります。これは以下のような形の文です。 for(var 変数名 in オブジェクト){} for(var key in obj){ console.log(key);} 左の変数に、右のオブジェクトが持っているプロパティの名前が入り、全てのプロパティについてループします console.log(obj[key]); 中身
従来(ES5以前)はプロパティの一覧にアクセスする方法はこれだけでしたが、ES5においては新しい方法が用意されました。 それはObject.keysメソッドです names.forEach(function(name){ console.log(obj[name]);});
- prototype のメソッドかどうかは ES5になってから気にすることが多くなったとのこと
for-in文はそのオブジェクト自身がもつプロパティだけでなくprototypeを介して参照するプロパティも列挙する
enumerable属性です。日本語にすると「列挙可能性」 enumerableがfalseの属性はfor-in文やObject.keysで列挙されない 属性は全部で3つあります。writable,enumerable,configurableで、いずれもtrueかfalseかです。 es5より前のjavascriptにおいてはこれらの属性は完全に内部的なもので、スクリプト側からどうこうすることはできませんでした。
属性(など)をいじるには、プロパティデスクリプタを使います。これはプロパティの属性を含む諸々の情報を表すオブジェクトです。Object.getOwnPropertyDescriptor var desc = Object.getOwnPropertyDescriptor(obj, "foo"); obj["foo"] についての情報を要求 { writable: true, enumerable: true, configurable: true, value: "bar" }
console.log(Object.getOwnPropertyDescriptor(Object.prototype,"toString"));
{ writable: true, enumerable: false, configurable: true, value: function toString() { [native code] } }
中身はブラウザの内部処理なのでjavascriptでは表現できないといういみ
Object.defineProperty
Object.defineProperty(obj,"hoge",{ writable:false, enumerable:true, configurable:true, value:"hogehoge" });
configurableがfalseであるプロパティの属性はいじれません。すなわち、definePropertyしようとするとエラーになります。 writableもfalseにしておけば、もはやそのプロパティの内容は絶対に不変であることが保証されたようなもの
Object.prototypeのようにいじられたら大惨事になるプロパティは、いじれないようにwritableとconfigurableがfalseになっています
実は、ゲッタとセッタについてもdefinePropertyを用いて設定できます
- defineProperty で get: とか set: に関数を磯ル (正式なやり方)
getとsetがある場合writable属性は無視されます valueもいりません
既存のプロパティに対してobject.definePropertyを使うこともできます 第三引数のオブジェクトで変えたいところだけを指定できる
作成時省略された属性はfalse
- object.defineProperties 複数プロパティを一度に作ったり変えたりする
- Object.defineProperties(obj,{ foo:{ value: "bar", configurable:true }, bar:{ value:3, enumerable:true } });
第二引数はオブジェクトで、設定したいプロパティ名をキーにしてプロパティデスクリプタを値としてもつ辞書オブジェクト
Object.getOwnPropertyNamesを紹介します。これは、基本はObject.keysと同じですが、enumerableがfalseのプロパティも列挙する
- Object.hasOwnProperty() 渡した名前のプロパティが自分自身にアるか Own なので、prototypeチェーン遡らない
enumerableがfalseなプロパティであっても正しく判定してくれます
in演算子というのがあります。これも同じようにプロパティが存在するかどうかを確かめる動作をしますが、prototypeチェーンまでさかのぼって探す console.log("attack" in zako); //true
このin演算子はfor-in文のinとはあまり関係ないので注意しましょう。
- Object.propertyIsEnumerable("propertyName") // true/false
- そもそもなかったら false
11-4 プロパティ話おわり (つづく) 2021/11/25 1:46 39m (いうほど、続く回での話は近い話ではなかった)
十一章第五回 プリミティブについて
https://uhyohyo.net/javascript/11_5.html
プリミティブはオブジェクト以外のもの
- JSの世界には 数値、文字列、真偽値、undefined,null, オブジェクトの六種類のものしかない
- hoge = "mojiretsu";
- typeof hoge; // "string"
- typeof では オブジェクトは "object" か "function" になる
- typeof では null は "object" になってしまう (歴史的経緯)
if(typeof a=="object"&&a!=null){。} とかかく
- プリミティブにプロパティはないが、. をつけるとString みたいなオブジェクトになる
プリミティブに対応したオブジェクトのインスタンスが一時的に作られる
nullとundefinedには対応するオブジェクトがないので変換できず、nullやundefinedのプロパティを参照しようとするとエラーになります。
"abc".charCodeAt(0)は97 a が 97 だから
"aaa".concat("bbb","ccc","ddd") // "aaabbbcccddd"
配列とは異なり文字列は+で繋げられるので使う機会はやや少ないかもしれません。
- 配列は + で繋げられないのかあ
"01234567890123456789".lastIndexOf("123") // 11
"012340123401234".indexOf("abc",2) // 6
- 検索開始位置指定できる これも0はじまり
lastIndexOfの場合、前から数えた位置を渡してあげるとその位置より後ろは無視されます。
a.localeCompare(b)
aのほうがbより先なら負の値、aとbが同じなら0、aのほうがbより後なら正の値
- 辞書順は必ずしもコードポイント順ではない
“n”(なんか上についてるやつ)は、コードポイントU+00F1を持ち、普通のaからzのアルファベット(U+0061?U+007A)よりずっと後ろにあります。ところが、localeCompareで比べると多くのブラウザではnはnとoの間にあるのではないかと思います。
localeCompareの第2引数に言語を指定することができます。言語は文字列で指定します。例えば日本語は"jp"で、英語は"en" IETF言語タグ
matchの場合はマッチに関する情報を配列で返して、replaceの場合は置き換え後の文字列 searchは位置番号
"abc123def".search(/\d/) // 3
"aaa,bb,c,dddd,ee".split(",") // ["aaa","bb","c","dddd","ee"]
"fff1ghi2jjjkkk0lmn".split(/\d/) // ["fff","ghi","jjjkkk","lmn"] - ☆なんと String.split() は正規表現もtukaeる
"fff1ghi2jjjkkk0lmn".split(/(\d)/) // ["fff","1","ghi","2","jjjkkk","0","lmn"] - ◎ ()でくくると、区切り文字が配列に入る
splitには第2引数があり、これがある場合配列の要素数の上限
toLowerCase, toUpperCase - 結構使うイメージ
- "Ω".toLowerCase() // "ω"
- "φ".toUpperCase() // "Φ"
- "a".toUpperCase() // "A"
toLocaleLowerCase, toLocaleUpperCase
- 言語に合わせて LowerとかUpperにする
言語設定がトルコ語の場合のみ"I".toLocaleLowerCase()が"?"などとなります
- ブラウザに言語設定があるので、引数でlocaleを指定しなくてもいい感じになるっぽい
- String.trim() も便利
読み終わり 2021/11/25 19:45 33m
十一章第六回 プリミティブについて2
https://uhyohyo.net/javascript/11_6.html
- 半壊は数値とか
- JSはぜんぶ Number
- Infinity NaN
- Infinity も number
- Number.POSITIVE_INFINITY
- 数学的に結果が決まらないときが NaN これも number
- console.log(typeof Number.NaN); // "number"
- NaNを含む計算の結果が全てNaNとなる
文字列から数値への変換時に、変換できない文字列はNaNになります
parseInt("123px") // 123
Number("123px") // NaN
parseInt("10000", 2) // 32 基数は、2から36まで可能
parseInt("z",36) // 35
- zまでしか文字がないから 36進数まで
- NaNが入ると比較は全てfalse
- isFinite (有限か)
- infinity や Nanでなければ true
nullもリテラルです。一方、実はundefinedはリテラルではなく変数ということになっています。スクリプト上にundefinedと書いた時はそれはundefinedのリテラルではなく、undefinedという値が入った変数が予め用意されているだけなのです。しかし、writable属性(十一章第四回参照)がfalseになっているので書き換えられません。
- 正規表現リテラルもあるぞ
- /ab+c/
マイナスがついたのはひとまとまりの数値リテラルではなく、単項演算子の-(マイナス)の後に数値リテラルがくっついた値であるということです。その証拠に、
- console.log(- 100);
- のようにマイナスを離しても動作します。
console.log(-num); // -10
- は 3.0 になる
- 1e4 // 10000
- 5.E2 // 500
- あとは16進数
- 0xff // 255
- 0xDEADBEEF // 3735928559
- console.log(num.toString(2)); // "1010"(2進法で10)
- 基数がある Number.toString()
console.log(a.toLocaleString()); // "30,000"
5.1.toFixed(5)//5.10000
123456.789.tofixed(2)//123456.79 四捨五入
- toExponential(小数点以下の桁数)
- toPrecision 有効数字
- NumberのメソッドはStringにするものばかり
- 3.toExponential(2) は 3.0toExponential(2) になるからエラーになる
- () とか .. にする
- Number.MAX_VALUE 扱える数値の範囲を出してくれる MIN_VALUE
Boolean.prototypeには特にメソッドはありません。
2021/11/26 23:19 40m
十一章第七回 継承2
https://uhyohyo.net/javascript/11_7.html
- 難しそう
ES5で可能になったよりよい継承の方法
- ソウソウョES3では なんか複雑な prototype といろいろを書かないと行けなかった
console.log(Object.getPrototypeOf(zako1) === Teki.prototype); // true
インスタンスの側からprototypeを取得できるのは、今までに無かったES5の新しい機能です(ただし、非標準のprotoというやつはありました)。
- インスタンスの方からprototype を取れるらしい
console.log(Teki.prototype.isPrototypeOf(zako1)); // true
instanceofとの違いは、コンストラクタに対して使うかprototypeオブジェクトに対して使うか
- isPrototypeOf は .prototype のメソッド
console.log(boss instanceof Teki); // true
- オブジェクトにつかえる instanceof
- 全部小文字なのか…
継承にかかわるのはDragonコンストラクタ内の Teki.apply(this,arguments); と、プロトタイプの Dragon.prototype = new Teki; のところでしたね。
- あまりに直感的でないES3のけいしうょ
- 継承したときに コンストラクタの処理がされるのが大問題
そこで、ES5ではこの問題を解決する方法があります。それがObject.createです
- うーん、 classはいつできたんだっけ
これは第一引数にプロトタイプオブジェクトを指定すると、それをプロトタイプに持つオブジェクトを作成します。つまりこんな具合です。
- var zako2=Object.create(Teki.prototype);
オブジェクトが他のコンストラクタのインスタンスであるかどうかは、オブジェクトと関連付けられたprototypeオブジェクトのみによって特徴付けられます (コンストラクタは呼ばれなくてもいいよ)
var zako2=Object.create(Teki.prototype);
- Teki.call(zako2);
2行目のcallは、Teki関数を、zako2をthisとして引数なしで呼べという意味ですね。コンストラクタはnewで呼ばれるときはthisの値が特別になっていたので、call(またはapply)を使ってそれを再現すればできます。
- コンストラクタも関数なのだった
Dragon.prototype = Object.create(Teki.prototype);
- のようにシンプルに継承できるらしい classがほしいね
Object.createに第2引数が渡された場合、インスタンスを作った後に第二引数で指定されたようにプロパティをセットして返してくれる
function Dragon(){ Teki.apply(this,arguments); } Dragon.prototype=Object.create(Teki.prototype,{ attack:{ configurable:true, value:function(){ console.log("ドラゴンのこうげき!!"); }, }, });
- うーんなるほどね (classしか使わなさそうな気がしている)
console.log(zako.constructor === Teki); // true
- コンストラクタを調べられる
実は、関数が作られた時点で、その関数のprototype.constructorにはその関数自身が自動的に入っている状態になります。
- なんとめんどくさいことに、 Dragon.prototype.constructor に Dragon を入れないといけない
おわり 2021/11/28 0:07 14m
十一章第八回 凍結と封印
https://uhyohyo.net/javascript/11_8.html
- かっこいい 2021/11/28 0:22 0m
オブジェクトに関するいくつかのメソッド オブジェクトに対する変更を制限
writable属性をfalseにすれば、個々のプロパティについては書き換え不能にすることができます。しかし、新しいプロパティを追加されるような事態に対しては対応不可能
Object.preventExtensions(obj);
delete演算子によりプロパティを削除することはできます 既存のプロパティに対する操作は自由にできます
- ◎ delete 演算子便利そう
Object.isExtensible() で調べられる 一度拡張不可能にされたオブジェクトは拡張可能に戻すことはできません。
- 多分 ↑が 凍結?ちがうか 拡張不可能カ
Object.sealです。順番が前後しますが、これが封印ですね。このメソッドは、オブジェクトを拡張不可能にするのに加えて全てのプロパティのconfigurable属性をfalseに設定します。 writable属性は変更されません。ということは、既存のプロパティは依然として変更可能
- なんか、実用では使わない気がしている…??
Object.isSealed
Object.freezeです。これが凍結 オブジェクトを拡張不可能にします。さらに、既存の全てのプロパティのconfigurable属性及びwritable属性をfalseにします。
- 拡張不可能よりつよい封印よりつよい凍結
Object.isFrozen
おわり 2021/11/28 0:31 9m
十一章第九回 strictモード
https://uhyohyo.net/javascript/11_9.html
- strictモードもES5から
- 厳格モード超推進派なuhyoさん (ここまでの講座でそういう面があまり見えなかったのが不思議な感じ)
- "use strict"; しってる
- script タグはしらんかった
- カンイウスコープも可能
- function foo(){ "use strict";
strictモードでは、varを使わずに変数を作ることはできません。 - 知らなかった
- グローバルスコープでvarでつくってね
- 変数名ミスをふせげるよ
argumentsですが、これは実はかなり曲者なオブジェクトで、その特殊な挙動はまさに闇と呼ぶにふさわしいものです。strictモードでは、argumentsのそのような特殊な挙動がなくなります。argumentsの闇に依存してしまうといけないのでこの講座ではそういったものを紹介していませんでしたが、もし興味がある人は調べてみるとよいでしょう(しかし利用してはいけません)。
strictモード内ではwith文という文を使うのは禁止されています。この講座ではwith文は紹介していませんので、気になる方は調べてみましょう。。。with文を禁止することで、javascriptをより最適化することができるそうです。
- なんか見かける気がする with
- 使わないように使用!
- 以外と strict モードのやってることは少なかった 2021/11/28 1:54 11m
終わり2021/11/28 1:56 13m
時間まとめ
- 11/23 - 11/28の 6日間
- 31 + 40 + 24 + 40 + 15 + 14 + 14 + 24 (ブログ) = 202分
- 一回あたり 20min だ
- 途中で 業務のTypeScript化の話をちょろっと書いた (10分)
全体の時間まとめ
- あと残ってる回が、7 + 4 + 5 + 5 + 22 + 7 + 1 = 51 回ある 1節10分なら 510分。 実は 1日1時間なら 9日で終わる。
- 実際には1節 20分で 1020分(17時間)では?
- ここまでは 6 + 4 + 14 + 6 + 3 + 3 + 3 + 6 + 4 + 8 + 4 + 9 = 70 回 1節10ふんなら 700分
- 実際には1節 20分で 1400分(23時間)では?
- ちゃんと足してみた
- 累計: 1114分 (= 18.6時間)
- 一回あたり 15.9分だった
- なので、あと 811分、 13.5時間で終わるだろう。
- 累計: 1114分 (= 18.6時間)
- 全部で 121回。 70/121 = 58%おわった
- 確かにマダまだ知らないことがあるね 2021/11/28 0:35 13m