カテゴリー別アーカイブ: javascript

【JavaScript】JavaScript問題集に追加しました。

フロントエンドエンジニア芸人もりたけんじのJavaScript【JavaScript】JavaScript中級者の為の練習問題集287問(脱初心者へ)2016/11/5更新

フロントエンドエンジニア芸人もりたけんじのJavaScript【JavaScript】JavaScript中級者の為の練習問題集287問(脱初心者へ)2016/11/05更新


こちらの記事も更新しました。

追加したいくつか。

問 location.href’で返す文字の最後が’/’かどうかを判定する関数を定義してください。
答えはこちらの問276のとこ
問 こちら、

var obj = {a : 1}
Reflct.get(obj, "a")
//1

Reflect.getを使って値を取得しています。
obj[“a”]
//1
との違いを教えてください。
ここの282問のとこ

とか。
もうちょっと理解深めて増やしたいと思います。
でわよい週末をーーーー。

https://github.com/kenmori/javascript/blob/master/README.md

【JavaScript】Reflectの使い方「Reflect | Metaprogramming in ES6: Part 2 – Reflect」の記事概要

【JavaScript】Reflectの使い方「Reflect | Metaprogramming in ES6: Part 2 - Reflect」の記事概要

【JavaScript】Reflectの使い方「Reflect | Metaprogramming in ES6: Part 2 – Reflect」の記事概要

以下ここの記事の概要

続きを読む

【JavaScript】Generatorを非同期処理

redux-sagaの中でよく見かける処理をもうちょっと根本から理解したいために写経してみる。
非同期処理を扱うgenerator。

generatorの基本

非同期時のコールバック地獄の一例

それを避けるためにgeneratorを使う

sleepは非同期処理が終わったらnext()を呼びだす

改善。setTimeout関数を外に切り出す(命令的な書き方)

並列処理の書き方

なるほどですね。。
あしたはもうちょっとgenerator理解進めて、coもみてみますね

参考

well-known Symbolとは| 海外記事「Detailed overview of well-known symbols」の和訳

%e3%82%b9%e3%82%af%e3%83%aa%e3%83%bc%e3%83%b3%e3%82%b7%e3%83%a7%e3%83%83%e3%83%88-2016-10-15-10-19-28
参照記事

SymbolはECMAScript2015の新しいプリミティブ型です。それはユニークな識別子を作ることができます

let uniqueKey = Symbol('SymbolName')

Symbolはオブジェクトの中のプロパティのkeyとして使うことが可能です。

(上のように使ったら)JavaScriptは「well-konwn symbols」として公開されたsymbolのリストを扱えます。

「Well-known symbols」はビルドインJavaScriptのアルゴリズムとして使われています。
例えば
Symbol.iterator はarrayやstringの要素を イテレートすること、もしくはあなた自身が定義したイテレーター関数などに利用されています。

それらの特別なSymbol等(ら)は重要です

なぜならそれらはオブクトのシステムプロパティで独自の振る舞いを定義できるからです。

それらをJSの中で使えるのです。

「唯一」として存在し、文字列イテレーターの代わりにkeyとしてシンボルを使うことは
新しいオブジェクトに新しい機能を追加することを簡単に可能にします

この記事ではwell-known Symbolのリストを通して、それらのコード中での快適な使い方を説明します

多くの場合単純化のために well-known Symbol.<name> は @@<name>形式に省略されています。

例えば

Symbol.iterator は @@iterator

Symbol.toPrimitiveは @@toPrimitive

「オブジェクトは @@iteratorメソッドを持つこと」を可能にすると言うことができます。

そのことは、オブジェクトはSymbol.iteratorと名付けられた、関数を所有するプロパティを持っていることを示しています。

{ [Symbol.iterator]: function(){...} }.

目次

  1. Symbolを短く紹介
  2. オブジェクトイテレータブルを作る@@iterator
  3. instanceofをカスタマイズする@@hasInstance
  4. オブジェクトをプリミティブに変換する@@toPrimitive
  5. オブジェクトのデフォルト記述を作成する@@toStringTag
  6. 派生されたオブジェクトを作成する@@species
  7. オブジェクトのような正規表現を作成 @@match, @@replace, @@search, @@split
  8. 配列要素に対してのオブジェクトをフラットにする@@isConcatSpreadable
  9. withの中のアクセス可能にするプロパティに対しての@@unscopables
  10. 終わりに

1.Symbolを短く紹介

Symbolは数値型、真偽値、文字列型のような唯一かつ不変なプリミティブ型です
symbolを作成するために、名前を引数とするオプションでSymbol関数を実行します。

  let mySymbol = Symbol();
  let namedSymbol = Symbol('myName');
  typeof mySymbol;
  //'symbol'
  typeof namedSymbol
  //'symbol'
  

mySymbolとnamedSymbolは symbolプリミティブです。 namedSymbolは ‘myName’ネームとの結びつきを持っていて、
それはデバッキングに対してよく使われます。

いつでもSymbol()が実行されることは重要で、
新しく且つユニークなsymbolが作られます。
2つのsymbolはたとえそれらが同じ名前を持っていてもユニークです。

  let first = Symbol();
  let second = Symbol();
  first === second;
  //false
  let firstNamed = Symbol('Lorem');
  let secondNamed = Symbol('Lorem');
  firstNamed === secondNamed; 
  //false
  

ユニークなシンボルで作られた first と second は違うものです。
firstNamed と secondNamed は ‘Lorem’ という同じ名前を持ちますが、違うものです

Symbols は オブジェクトのプロパティに対してkeyになることができます。
オブジェクトリテラル それか クラス定義の中で、
コンピューティッドプロパティネーム構文の [symbol]は使用は不可欠です。

  let stringSymbol = Symbol('String');
  let myObject = {
   number: 1,
   [stringSymbol]: 'Hello World'
 };
  myObject[stringSymbol];//'Hello World'
  Object.getOwnPropertyNames(myObject); //['number']
  Object.getOwnPropertySymbols(myObject);//['Symbol(String)']
  
  

リテラルからmyObjectを定義している際、コンピューティッド構文はsymbol[stringSymbol]からのプロパティkeyを設定するために使われます。

シンボルで定義されたプロパティはObject.keys()やObject.getOwnPropertyNames()関数を使ってアクセスできません。

それらにアクセスするためには特別な関数であるObject.getOwnPropertySymbols()を呼びます。

keyとしてシンボルを使うことは重要な観点です。
特別なSymbol(well-known symbols)はイテレーションやプリミティブなオブジェクト、文字変換等のようなカスタムオブジェクトを定義することを可能にします。

well-known symbolsは列挙不可、書き換え不可、再設定不可 を可能にした Symbol関数オブジェクトのプロパティです
単純、Symbol.iteratorやSymbol.hasInstance等、それらを得るためのSymbol関数オブジェクト上のプロパティアクセサーを使います

このようなwell-known symbolsのリストを得ることができます。

Object.getOwnPropertyNames(Symbol);
//["hasInstance", "isConcatSpreadable", "iterator", "toPrimitive", "toStringTag", "unscopables","match", "replace", "search", "split", "species", ...];
typeof Symbol.iterator; 
//'symbol'

Object.getOwnPropertiesNames(Symbol) は Symbol関数オブジェクトの所有されたプロパティを返し、
well-known symbolsのリストを含んでいます。
Symbol.iteratorの進む「型」は’symbol’です。

オブジェクトイテレータブルを作る@@iterator

Symbol.iteratorは多分より知られているsymbolです。
それはオブジェクトがfor…of文やスピリードオペレータによってどのように使われ、イテレートされるべきかを定義することを可能にします

多くのstrings、arrays、maps、sets、などのビルドイン型はイテレータブルで、@@iteratorメソッドを持ちます。

let myString = 'Hola'
typeof myString[Symbol.iterator];// 'function'
for(let char of myString) {
 console.log(char); //logs on each iterator 'H', 'o', 'I', 'a'
}
[...myString];// ['H', 'o', 'I', 'a']

文字列のプリミティブ型のmyString はSymbol.iteratorプロパティを持ちます。
プロパティは文字列のキャラクターをイテレートすることに使うメソッドを所有します。

Symbol.iteratore という名前のメソッドを定義するオブジェクトはイテラブルプロトコルに準拠しています。
メソッドは イテレータープロトコルに準拠したオブジェクトを返す必要があります。

イテレータプロトコルオブジェクトは{value: , done: }を返すnext()メソッドを持つ必要があります。

カスタムイテレータの定義の仕方を理解しましょう。
下の例はmyMethods というイテラブルオブジェクトを作成、myMethodsはメソッドの所有を可能にします。

  function methodsIterator(){
   let index = 0;
   let methods = Object.keys(this).filter((key) = &gt; {
     return typeof this[key] === 'function';
   }).map(key =&gt; this[key]);
   return {
     next: ()=&gt; ({//Conform to Iteretor protocol
      done: index &gt;= methods.length,
      value: methods[index++]
     })
   };
  }
  let myMethods = {
    toString: function(){
     return '[object myMethods]';
    },
    sumNumbers: function(a, b) {
     return a + b;
    },
    numbers: [1,5,6],
    [Symbol.iterator]: methodsIterator //Comform to Iteratable Protocol
  };
  for ( let method of myMethods) {
     console.log(method); //logs methods `toString` and `sumNumbers`
   }

methodsIterator() は イテレーターオブジェクト{next : function(){…}}を返す関数です。
myMethodsの中でオブジェクトプロパティはkeyとしてSymbol.iterator、値としてmethodsIteratorがセットアップされます

これはmyMethods をイテラブルにさせ、
for…ofループの中のsumNumbers()とtoString()らのオブジェクトが所有するメソッドを渡すことができます

それに加えて、[…myMethods]かArray.from(myMethods)を呼ぶことによってそれ等のメソッドを得ることができます。

@@iterator プロパティ は ジェネレーター関数も受け取り、そのジェネレーター関数を値にさせることもできます

@@iteratorメソッドでFibonacci シーケンスを生成する class Fibonacci を作ってみましょう

  class Fibonacci {  
  constructor(n) {
    this.n = n;    
  }
  *[Symbol.iterator]() {
    let a = 0, b = 1, index = 0;
    while (index &lt; this.n) { index++; let current = a; a = b; b = current + a; yield current; } } } let sequence = new Fibonacci(6); let numbers = [...sequence]; numbers; // =&gt; [0, 1, 1, 2, 3, 5]
  

*[Symbol.iterator](){…} はジェネレーター関数はクラスメソッドということを明らかにします。
Fibonacciクラスのインスタンスはイテラブルプロトコルに準拠します。

そしてシーケンスインスタンスは[…sequence]スプレッドオペレーターで使われます。
スプレッドオペレーターは生成された数値からの配列を作成するために@@iterator メソッドを呼びます。

なので 結果は最初のFibonacci 数値の5の配列です。

もしプリミティブ型かオブジェクトが@@iteratorメソッドを持つなら、それらは下のコンストラクタ内で適応することができます。

・for…ofループの中での要素を超えイテレートする
・スプレッドオペレータ[…iterableObject]を使って要素の配列を作成する
・Array.from(iterableObject)を使って要素の配列を作成する
・他のジェネレーターへの代理する為のyield*式の中で
・Map(iterableObject)、WeakMap(iterableObject)、Set(iterableObject)、WeakSet(iterableObject)に対してのコンストラクタの中で
・静的メソッドPromise.all(iterableObject)、Promise.race(iterableObject)であるPromiseの中で

instanceofをカスタマイズする@@hasInstance

デフォルトでは obj instanceof Constructor オペレーターはConstructor.prototypeオブジェクトを含むObjectのprototypeのチェーンかどうか検証する
例題をみていきましょう

function Constructor(){
//constructor code
}
let obj = new Constructor();
let objProto = Object.getPrototypeOf(obj);
objProto === Constructor.prototype // true
obj instanceof Construcotr;//true
obj instanceof Object;//true

obj instanceof Constructor はtrueかを評価します。なぜならobjのprototypeはConstructor.prototypeと同等だからです。
instanceof 検証はobjのprototypeチェーンも検証し、したがって、
obj instanceof Object は trueです。

多くのアプリケーションはprototypeに対処し、instanceの検証を必要としません

幸い、カスタマイズのinstanceof 評価を呼ぶことができる@@hasInstancseを定義できます。
obj instance Type はType[Symbol.hasInstance](obj)と同等です。

例えば、もしobjectかプリミティブがイテラブルの場合の検証をしましょう。

class Iterable {  
  static [Symbol.hasInstance](obj) {
    return typeof obj[Symbol.iterator] === 'function';
  }
}
let array = [1, 5, 5];  
let string = 'Welcome';  
let number = 15;  
array instanceof Iterable;  // =&gt; true  
string instanceof Iterable; // =&gt; true  
number instanceof Iterable; // =&gt; false 
  

イテラブルは@@hasInstance静的メソッドを含むクラスです。
このメソッドは供給されたobjパラメータがイテラブルか検証します
後のイテラブルかは違うタイプの値か検証に使われます
配列と文字列は はイテラブルで数値はそうではありません

個人的に単にinstanceof と constructorで@@hasInstanceを使うことは
isIterable(array)を呼ぶより
嬉しいです。

array instanceof Iterable は配列がイテラブルプロトコルに準拠しているかの検証されることとしてオススメします。

オブジェクトをプリミティブに変換する@@toPrimitive

プロパティの値記述としてのSymbol.toPrimitive 使用はオブジェクトからプリミティブへの変換する関数です。
@@toPrimitive メソッドは1つのnumberかstringかデフォルトを取るパラメーター[ヒント]を持ちます。
ヒントパラメーターは返すべきプリミティブの型の提案を示します

例えば 配列インスタンスを@@toPrimitiveメソッドで改善しましょう。

  function arrayToPrimitive(hint) {  
  if (hint === 'number') {
    return this.reduce((sum, num) =&gt; sum + num);
  } else if (hint === 'string') {
    return `[${this.join(', ')}]`;
  } else {
    // hint is default
    return this.toString();    
  }
}
let array = [1, 5, 3];  
array[Symbol.toPrimitive] = arrayToPrimitive;  
// array to number. hint is 'number'
+ array; // =&gt; 9
// array to string. hint is 'string'
`array is ${array}`; // =&gt; 'array is [1, 5, 3]'
// array to default. hint is 'default'
'array elements: ' + array; // =&gt; 'array elements: 1,5,3'  
  

arrayToPrimitive(hint) は配列をhintから独立しているプリミティブへ変換する関数です

その割り当てである array[Symbol.toPrimitive] = arrayToPrimitive は新しい変換メソッドを使えるように配列を作ります。

+array は@@toPrimitiveメソッドを’number’で呼びます。

配列は数値に変換され、9の要素配列の合計です。
プリミティブ変換は'[1, 5, 3]’
最後の ‘array elements: ‘ + arry は変換用のhintデフォルトを使います。
この場合 arrayは’1,5,3’に評価されます。

@@toPrimitive メソッドは オブジェクトがプリミティブ型と相互作用するとき使われます。
・object == primitive 同等操作の中で
・追加、連結操作 object + primitive
・減算操作の中で object – primitive
・オブジェクトがプリミティブへ強制されたときの違う状況で String(object), Number(objet)

オブジェクトのデフォルト記述を作成する@@toStringTag

 

プロパティを示すためにSymbol.toStringTagを使います。プロパティの値はオブジェクト型が記述された文字列です。

@@toStringTag メソッドは Object.prototype.toString()として使われています。

Object.prototype.toString()の仕様書は多くのJavaScript型はデフォルトとしてタグを持っていることを示します。

let toString = Object.prototype.toString;  
toString.call(undefined); // =&gt; '[object Undefined]'  
toString.call(null);      // =&gt; '[object Null]'  
toString.call([1, 4]);    // =&gt; '[object Array]'  
toString.call('Hello');   // =&gt; '[object String]'  
toString.call(15);        // =&gt; '[object Number]'  
toString.call(true);      // =&gt; '[object Boolean]'  
// etc for Function, Arguments, Error, Date, RegExp
toString.call({});        // =&gt; '[object Object]'  

これらの型はプロパティSymbol.toStringTagを持っていません。
しかしObject.prototype.toString()アルゴリズムはそれらとは分けて評価します。

多くの他のJavaScript型はSymbol、ジェネレーター関数、maps、promises、など、で@@toStringTagプロパティを定義します。
ちょっと見てみましょう。

let toString = Object.prototype.toString;  
let noop = function() {};

Symbol.iterator[Symbol.toStringTag];   // =&gt; 'Symbol'  
(function* () {})[Symbol.toStringTag]; // =&gt; 'GeneratorFunction'
new Map()[Symbol.toStringTag];         // =&gt; 'Map'  
new Promise(noop)[Symbol.toStringTag]; // =&gt; 'Promise'

toString.call(Symbol.iterator);   // =&gt; '[object Symbol]'  
toString.call(function* () {});   // =&gt; '[object GeneratorFunction]'  
toString.call(new Map());         // =&gt; '[object Map]'  
toString.call(new Promise(noop)); // =&gt; '[object Promise]'  

上のサンプルでみるように、
多くのJavaScript型はそれらが所有する@@toStringTagプロパティを定義します。

オブジェクトが型や@@toStringTagプロパティが提供されていない他のケースでは
単に’Object’としてタグされます。
もちろん@@toStringTagプロパティでカスタム定義できます。

let toString = Object.prototype.toString;

class SimpleClass {}  
toString.call(new SimpleClass); // =&gt; '[object Object]'

class MyTypeClass {  
  constructor() {
    this[Symbol.toStringTag] = 'MyType';
  }
}
toString.call(new MyTypeClass); // =&gt; '[object MyType]'
"[object MyType]"

new SimpleClass インスタンスは @@toStringTagが定義されていなかった。
Object.prototype.toString()はそれに対してデフォルトの'[object Object]’を返します。
MyTypeClassコンストラクタの中で、インスタンスはカスタムタグ’MyType’で設定されました。

そのようなObject.prototype.toString()クラスインスタンスに対してカスタム型記述は'[object MyType]’を返します。

@@toStringTagは下位互換の点で存在していることに注意してください。

その習慣はなやましいです。
あなたは他のオブジェクト型の線引きするための違う方法(instanceofかtypeof のような)を使うべきと思うだろう

派生オブジェクトを作成する@@species

Symbol.speciesプロパティの値は派生オブジェクト を作成するために使われたコンストラクタ関数です。
多くのJavaScriptコンストラクタはコンストラクタ自身と同等の@@speciesの値を持っています。

Array[Symbol.species] === Array;   // => true  
Map[Symbol.species] === Map;       // => true  
RegExp[Symbol.species] === RegExp; // => true  

最初に注意したいのは派生オブジェクトは元のオブジェクト上の操作後に作成されるものです。
例えばオリジナルな配列上の.map()メソッドを呼ぶと、派生オブジェクトを返します(配列結果をマッピングした)

大抵、派生オブジェクトはオリジナルのオブジェクトとして同じコンストラクタを持ち、もっていることを期待されます。
しかし時々カスタムコンストラクタを示すことが必要になります。

@@speciesプロパティはその助けとなります。

Arrayコンストラクタを子classのMyArrayとして使いやすいメソッドを加えるために拡張する際のシナリオを想定してください。

後でMyArray classインスタンスがmap()で使われるとき、
Arrayのインスタンスである必要があり、MyArrayはその子供ではない場合、それをします。

@@speciesプロパティアクセサを定義し派生したArrayコンストラクタオブジェクトを示します。

class MyArray extends Array {  
  isEmpty() {//拡張
    return this.length === 0;
  }
  static get [Symbol.species]() {//プロパティアクセサを定義する
    return Array;//派生オブジェクトを示す
  }
}
let array = new MyArray(3, 5, 4);  
array.isEmpty(); // => false  
let odds = array.filter(item => item % 2 === 1);  
odds instanceof Array;   // => true  
odds instanceof MyArray; // => false  //違うことを示す

静的アクセさプロパティのMyArrayでstatic get [Symbol.species](){}が定義されています。
それは派生オブジェクトはArrayコンストラクタを持つべきだという指示です。
array.filter()メソッドはArrayを返し、配列要素を選別した後に

@@species アクセサプロパティは.map()、.concat()、.slice()、.splice()のようなArrayとTypeArrayメソッドで使われ、派生オブジェクトを返します。
それはmaps、正規表現オブジェクト、プロミスなどの拡張しているものに対して有効で、オリジナルコンストラクタをキープできるのです。

オブジェクトのような正規表現を作成 @@match, @@replace, @@search, @@split

JavaScriptのString プロトタイプは 正規表現オブジェクトを受け入れる4つのメソッドを持っています。

・String.prototype.match(regExp)
・String.prototype.replace(regExp, newSubstr)
・String.prototype.search(regExp)
・String.prototype.split(regExp, limit)

ECMAScript 2015は それらの4つのメソッドは正規表現以外のタイプをプロパティの値とされた結果の関数を「条件」を定義することで、受け入れることができます。

@@match, @@replace, @@search and @@split.

面白いことにそれらのメソッドが定義された正規表現prototypeはsymbolを使うことで定義できます

typeof RegExp.prototype[Symbol.match];   // => 'function'  
typeof RegExp.prototype[Symbol.replace]; // => 'function'  
typeof RegExp.prototype[Symbol.search];  // => 'function'  
typeof RegExp.prototype[Symbol.split];   // => 'function'  

カスタムパターンclassを作成してみましょう。
下の例はRegExpの代わりに使うことができる単純なclass定義です。

class Expression {  
  constructor(pattern) {
    this.pattern = pattern;
  }
  [Symbol.match](str) {
    return str.includes(this.pattern);
  }
  [Symbol.replace](str, replace) {
    return str.split(this.pattern).join(replace);
  }
  [Symbol.search](str) {
      return str.indexOf(this.pattern);
  }
  [Symbol.split](str) {
      return str.split(this.pattern);
  }
}
let sunExp = new Expression('sun');  
'sunny day'.match(sunExp);            // => true  
'rainy day'.match(sunExp);            // => false  
'sunny day'.replace(sunExp, 'rainy'); // => 'rainy day'  
"It's sunny".search(sunExp);          // => 5
"daysunnight".split(sunExp);          // => ['day', 'night']

Expression classは@@match, @@replace, @@search and @@split. を定義しています。
後のsunExp インスタンスは 返すstring メソッドで使われて、だいたい擬似的な正規表現です。

配列要素に対してのオブジェクトをフラットにする@@isConcatSpreadable

————————————————-
以降はただいま翻訳中。。
長いな。。あと3つか。。

withの中のアクセス可能にするプロパティに対しての@@unscopables

終わりに

JavaScript問題集にgenerator関数を追加

こちらのJavaScript問題集
263問目からgenerator関数の問題を多めに追加しました。
redux-sagaでここの理解は必須のようなので強化した。

あと随時、Proxy、Symbol、Reflect、Promise、async/await などを追加したい。

一旦この辺でーー
でわまたーーー

わたしもみている| Immutable Javascript using ES6 and beyond(Array)

前回ここのObjectまで読みました。

今回はArray
immutableなArray。
非破壊メソッドを使おう

pushの代わりに、
Spread Operator

let characters = ['a', 'b'];
let newCharactors = [...characters, 'c'];
console.log(newCharactors === characters)
//false
console.log(characters)
//["a", "b"]
newCharactors
//["a", "b", "c"]
//要素b以外の新しい配列を返す
const whithout = characters.filter(char => char !== 'b');
whithout
//["a"]

//要素bとcを入れ替えた新しい配列を返す
const backInTime = characters.map(char => char === 'b' ? 'c' :char);
backInTime
//["a", "c"]

//大文字にした新しい配列を返す
const shoutOut = characters.map( char => char.toUpperCase())
shoutOut
//["A", "B"]

//2つの配列を足した新しい配列を返す
let characters = ['a', 'b'];
const otherCharacters = ['d','e'];
const moreCharacters = [...characters, ...otherCharacters]
moreCharacters
//["a", "b", "d", "e"]

sort()の返り値とオリジナルの参照先は変わらない。要素順だけ入れ替える

const characters2 = ["b", "d", "a", "c"];
const sortedCharacters = characters2.sort()
sortedCharacters
//["a", "b", "c", "d"]
sortedCharacters === characters2
//true

順序を入れ替えた上で新しい配列を返すにはsliceを使う

const sortedCharacters2 = characters2.slice().sort();
sortedCharacters2 === characters2
//false
characters2
//["a", "b", "c", "d"]
sortedCharacters2
//["a", "b", "c", "d"]

なぜ新しいオブジェクトを生成する方がいいのか??
そんなに新しいオブジェクトを生成してメモリは大丈夫なの??

But that disadvantage is very small compared to the advantages.
欠点は利点に比べて非常に小さいです

One of the more complicated operations in Javascript is tracking if an object changed
JSでより複雑な操作の一つはオブジェクトが変更された場合の追跡です

Object.observe(object, callback) are pretty heavy
Object.observeは相当重たいです。
※記事が古いのか、Object.observeは今では廃止されています

if you keep your state immutable you can just rely on oldObject === newObject to check if state changed or not, this is way less CPU demanding.

もしオブジェクトの状態を不変に保てば古いオブジェクトか新しいオブジェクトかどうかのチェックは
oldObjet === newObject だけで可能だし、これはCPUへのダメージが少ない方法です

Second big advantage is code quality. Making sure your state is immutable forces you to think better of your application structure. It encourages programming in a more functional way, makes your code easy to follow and reduces the possibility of nasty bugs. Win, win, right?
第二の大きなアドバンテージはコードの品質です。
状態を確認することは不変オブジェクトがなせることです。
これはアプリケーションの構築への良い考えなのです
It encourages programming in a more functional way, makes your code easy to follow and reduces the possibility of nasty bugs.
より関数型なプログラミングを奨励します。バグを除き、コードを追いやすくするのです

Reference
Immutable Javascript using ES6 and beyond

Chrome (DeveloperTools)デベロッパーツールでJavaScript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

実際にデバッグを覚えたい方への記事です。
こちらを使って。

環境
Mac、chromeです。

モチベーション
JS入りたての頃のわたしはデバッグ記事の少なさとそれをハンズオンで教えてくれる記事があまりないことに弱っていました。その頃英語記事アレルギーもありました。
実際デバッグの方法を細かく教えてもらえたらなぁ。っていう過去の自分みたいな方多いのではないかと思いました。
(今回の記事はデバッグの方法を全く知らない人向けではありませんが。。)

デバッグができるようになるとエラーに尻込みしなくなるし、時間が短縮されますよね。

今回は表題の通り
「chrome (developerTools)デベロッパーツールでJavaScript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法」
です。

やること
こちらをクリックしてください。gifアニメが動きます。(約2分, PC奨励)
1

こちら何をしているか写真で説明しますので先ほどのコードをご用意してブラウザ上でindex.htmlを表示させてみてください。

ハンズオン
コード上のここ
にエラーを発生させています。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

1

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

・ファイルをロードするとコンソールにエラーが出ています。(yが未定義のようです)

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

2
・ここでshift + cmd + p押してください

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

で「sou」まで打ってパーーンっとしてみてください。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

ソースパネルまで飛んだと思います。

3
そのソースパネル上で、
option + o 。をしてください。

ファイル検索できます。(いちいち左のツリーをクリックして探さなくていいってことです。)

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

余裕があったらソースパネル上で、
shift + cmd + o を押してみてください。
関数が出てくると思います。もしあらかじめffがおかしいと疑えてたらff()のところまでジャンプできます。

main.jsのエラーでしたのでmainまで打てば行けます

赤くなっています。。秋ですね。。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

つまり1 + xと加算したかったのを
yを記述したせいで、
スコープ内にもyがない、、
辿っていったスコープ内にもない、、
グローバルスコープにもyがない、、
yは未定義。
とされてここで処理がとまっているのです。
ここをどうにか直したい。
どう直せばいいか分かっている場合、
ファイルに戻ってxと書き直すのもいいですが、

こちらが直ってもこの先にもし、
なんらかのエラーがあった場合また処理が止まります。

ここで編集して実行、反映させることで

・その先のエラーがあるかないかまで見れる。
・違う変数や処理を追加 or 削除などその場で試せる。
・ここでの修正をローカルファイルに反映することができる。

のですね。

4
ブレイクポイントを仕込んでください。赤くなっている箇所に行番号をクリックです

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

ブレイクポイントはその行で実行を止めて、スコープの範囲の変数に何が代入されているか、何を参照しているか確認できます。
※実際コンソールタブまで移動してcondole.log(y)とすればundefinedが返ってくると思います

話戻して、

5

yをxと書き換えます。このように
※リロードしないでくださいね。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

6

編集し終わったらsaveしてください(cmd + s)
するとファイルの背景がピンクになります(gifアニメーションではなりませんでしたが)

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

7

でここ押してください。(したの方で青くなっている矢印の横にある「step into next function」「関数の中に入って行って、一行一行処理を進めるボタン」です)chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

すると処理が進んでscopeの変数が7を返しているのがパネルからわかります。ローカル変数がxを参照して期待する通り、1 + x として加算されたのですね。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

8

実際ホーバーしてみてください。代入されていることが確認できます。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

先ほどのボタンを推し進めていくとconsole.logを実行する箇所がありますね。
先ほどまではここまでたどり着きませんでした。
なぜならエラーで処理がとまっていたからです。

このように処理を正しく記述、ブラウザ編集することで
その実行を止めないで進めることができます。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

9

consoleタブに移動してコンソール出力をみてください。
7とあるはずです。

その先もエラーがなく処理を終えたみたいです。

10

先ほどの編集したJSファイルをセーブしましょう。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

エディターの該当箇所もそれを反映しているはずです。
6_13

11
リロードすると。。

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

chrome (developerTools)デベロッパーツールでjavascript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法

エラーが消えました。(ブラウザ上の編集がエディタのコードに反映されて)

※ローカルで編集しているファイルと実際の実行ファイルが同じ参照先にあれば同期されます。
※ミニファイやwebpackで書き出したファイルは大元のファイルを修正する必要が有るかもしれませんね。

Chrome (DeveloperTools)デベロッパーツールでJavaScript実行時エラー、処理を止めないようにブレイクポイント(使い方)編集、それをローカル保存する方法
でしたーー

実際のコード(エラーがでるコード)をこちらにあげておきますので、
ローカルにダウンロードして、確かめてみてくださいー。

ありがとうございましたーーー

ではーーー

【JavaScript】問題集を更新しました

以下は問題集に追加した一部です。

元記事はこちら
————————————-
こちら、const myObject = {1: [‘e’, ‘ee’, ‘eee’], 2: [‘f’, ‘ff’,’fff’]};を多次元配列にしてください
期待する結果:[[‘e’,’ee’,’eee’],[‘f’,’ff’, ‘fff’]];

const myObject  = {1: ['e', 'ee', 'eee'], 2: ['f', 'ff','fff']};
const newArr = Object.keys(myObject).map(function(elem){
   return myObject[elem]
})
//[[‘e’,’ee’,’eee’],[‘f’,’ff’, ‘fff’]]

//other
const myObject  = {1: ['ee', 'eee', 'efe'], 2: ['faf', 'fafa','fa']};
const arr = Object.values(myObject);
//※Object.values(ECMAScript2017)を使える環境で(Polyfill: es-shims/Object.values,tc39/proposal-object-values-entries)で

こちら[‘a’,’b’,’c’] → {0: ‘a’, 1: ‘b’, 2: ‘c’}のように、インデックスをキーにして、配列要素をそれぞれの値となるようにしてください

//1
const arry = ['a', 'b', 'c'];
function toObject(arry){
 const obj = {};
 const len =  arry.length;
 for(let i=0; i < len; i++){
  obj[i] = arry[i]
 }
 return obj
}
toObject(arry)
//{0: "a", 1: "b", 2: "c"}

//2
const arry = ['a', 'b', 'c'];
const obj = arry.reduce(function(o, v, i){
 o[i] = v;
 return o;
},{})
obj
//{0: "a", 1: "b", 2: "c"}

でわーーー

わたしもみている | Immutable Javascript using ES6 and beyond(Object)

過去にこういう記事書いて
Immutable.jsを使って参照等価性を保証するのと、Object.assignやArray.reduceを使ってそれするのと何が違うんだろうと思って、
lmmutable.jsを使うユースケースはどんな時かを探っていました。
「 Immutable Javascript using ES6 and beyond」は「lmmutable.JS vs ECMAScript2015」したら出てきた記事です

const person = {
 name: 'john',
 age : 28
}
const newPerson = person;
newPerson.age = 30;
newPerson === person 
//true
person
// {name: "john", age: 30}

これは参照元のageを書き換えてしまいます。
厳密等価演算子でもtrue

freezeしても。。

const myObject = {a: {b: 1}, c: 2};
Object.freeze(myObject);
myObject.a.d = 2; 
myObject
// {a: {b: 1, d: 2}, c: 2}

子供オブジェクトはfreezeできない。

不変オブジェクトにするには、、

const person = {
  name: 'John',
  age: 28
}
const newPerson = Object.assign({}, person, {
  age: 30
})
console.log(newPerson === person) // false
console.log(person) // { name: 'John', age: 28 }
console.log(newPerson) // { name: 'John', age: 30 }

新しいオブジェクトを返します。比較はfalseで同じ参照をもちません。
ちなみにObject.assign()の第一引数にpersonを渡すと、参照元のpersonも上書きますよね。

ここからがへぇだったのですが、
babel-stage2、experimental ES7 draftsでは
下のようなobject spread が使えます

const person = {
  name: 'John',
  age: 28
}
const newPerson = {
 ...person,
 age: 30
}
console.log(newPerson === person);
//false
console.log(newPerson)
//{"age": 30,  "name": "John"}//overrideします

コード

これはいい。。
これだとassignいりませんね。
…はそのオブジェクトをコピーしています。
ageはoverrideしています。
なので上のコードでもし

const newPerson = {
 age: 30,
 ...person
}

こうした場合、
ageは28です。

const obj1 = {a: 1};
const obj2 = {b: 2};

const obj3 = {...obj1,...obj2};
console.log(obj3)
//{"a": 1,"b": 2}

記事ではオブジェクトを削除する方法もあります。
ただこの方法は不変性に欠ける、なぜコードを多く書いて、オブジェクトを配列にして、操作しないといけないのかを問うています。

お時間です。
あしたはArrayの方を追ってみようと思います。

Reference:
Immutable Javascript using ES6 and beyond

【関連記事】
【Immutable.jsの使い方】Immutable.js超入門~ReactでsetStateのプロパティ値に直接代入避ける~

【JavaScript/関数型プログラミング】抽象化

p3
http://underscorejs.org/のコンソールで試す
※underscore.jsを使っています

function splat(fun){
 return function(array){
   return fun.apply(null, array);
 }
}
var arrayelem = splat(function(x, y){ return x + y});
arrayelem([1, 2])
//3

関数と配列を渡して呼ぶとその配列を関数の引数として実行することができる

function unsplat(fun){
 return function(a, b){
  return fun.call(null, _.toArray(arguments));
 }
}
var fff = unsplat(function(array){return array.join(' ')});
fff(1,2);
"1 2"
fff('-', '$', '/', '!', ':');
"- $ / ! :"

データと動作を隠蔽するということは関数を抽象の単位にする方法のひとつにすぎない
抽象とは個別の基本的な動作を保持し、あちこちで使い回すための簡単な方法を提供すること

var letter = ['a','b','c'];
letter[1];
//"b"

配列のインデックス指定という基本動作を使い回すには
関数に閉じ込めておく以外に方法がない

function nth(a, index){
 return a[index];
}
nth(letter, 1)
//"b"

nth関数はインデックス指定可能なデータ型をもったデータから、有効なインデックスで指定される要素を返す

しかし予測しない動作をする
nth({}, 1)
undefined

与えられたものがインデックス指定可能なデータ型かどうか見分けるためにisIndexed関数を作る
抽象を提供する関数

function isIndexed(data){
 return _.isArray(data) || _.isString(data);
}

//抽象と別の抽象を組み合わせることでhthの完全な実装を行うことができる

function nth(a, index){
  if(!_.isNumber(index)) console.log("indexは数値である必要があります");
  if(!isIndexed(a)) console.log("インデックス指定可能でないデータ型です");
  if((index < 0) || (index > a.length -1 )) console.log("指定されたインデックスは範囲外です");
  return a[index]; 
}
nth({}, 1)
//インデックス指定可能でないデータ型です
nth(1, 1)
//インデックス指定可能でないデータ型です
nth([1,3],{})
//indexは数値である必要があります
nth('abc', 0)
//"a"
nth([2,4,5], 1)
//4

isIndexed関数を使ってnthを抽象化したのと同様に2番目の要素を返す動作を抽象化したsecond関数を作ることができる

function second (a){
  return nth(a, 1);
}
second(['a','b','c'])
//"b"
second("fogs");
//"o"
second({})
//インデックス指定可能でないデータ型です

second関数を使ってnth関数の動作と異なる、しかし関連性のあるユースケースをあてがうことができる