関数名の展開
- 関数式の関数名問題:
ES5では、変数自体の関数代入はname属性がないため、関数名は''と表示されますが、ES6では
var f = function(){}
console.log(f.name); //f
- new Function()
関数を宣言する場合、実際にはFunctionコンストラクタをインスタンス化するため、new Functionを使用して関数を宣言することは推奨されません。
しかし、new Functionのname属性がname属性と同じではないことを知っておくことは重要です。
console.log(new Function().name); //anonymous(匿名)
- bind
function foo(){}
console.log(foo.bind({}).name); //bound foo
callはbindとは異なります。なぜならcallは関数の実行であり、関数は実行後に名前を持たないからです。
function foo(){}
console.log(foo.call({}).name); //
オブジェクトの展開
属性名は文字列として処理されます。
例 1:
var arr = [5,6,8,88];
console.log(arr['1']); //5配列も特殊な変数である
例 2:
let a = 'hello';
let b = 'world';
let obj = {
[a + b] = true;
}
例 3:
var myObj = {};
myObj[true] = 'foo';
myObj[3] = 'bar';
myObj[myObj] = 'baz';
console.log(myObj); //{'true':'foo','3':'bar','myObj':'baz'}
文字列として扱われる属性は暗黙的に変換されます。
trueと3はプロトタイプのtoStringメソッドで文字列に変換され、myObjはtoStringメソッドで[Object Object]に変換されるので、bazは[Object Object]から直接アクセスできます。
console.log(myObj["[object Object]"]); //baz
例 4:
const a = {a: 1};
const b = {b: 2};
const obj = {
[a]: 'valueA',
[b]: 'valueB'
}
console.log(obj); //{[object Object]: 'valueB'}
変数への参照は括弧で囲む必要があります。そうしないと {a: "valueA", b: "valueB"} となり、参照なしで直接変換されます。
オブジェクトメソッド名の取得
const person = {
sayName(){
console.log('hello');
}
}
console.log(person.sayName.name); //sayName
プロパティ記述子 getOwnPropertyDescriptor
ES5にはプロパティの特性を検出するメソッドがありませんが、ES6にはプロパティ記述子が用意されています。
let obj = {a: 2};
console.log(Object.getOwnPropertyDescriptor(obj, 'a'));
渡されたプロパティが文字列
configurable: true //設定可能
enumerable: true //列挙可能
value: 2
writable: true //
defineProperty は新しいプロパティを変更・追加します。
let obj = {};
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: true, //falseそして、definePropertyで設定することができなくなる。
configurable: true,
writable: false //書き込みはできないが、削除はできる
})
obj.a = 3;//書き込み可能ではないので、このステートメントはエラーを報告せずに失敗するが、ストリクト・モードではエラーを報告する。
console.log(obj); //{a: 2}
console.log(Object.defineProperty(obj, 'a'));
delete obj.a;
console.log(obj); //{}
falseに設定されたwritableは書き込み不可のみで、削除不可はconfigurableがfalseの場合のみ可能です。
defineProperties
var obj = {};
Object.defineProperties(obj, {
a: {
value: true,
writable: true
},
b: {
value: 'hello',
writable: true
}
})
getter / setter
取得操作
let obj = {a: 1};
obj.a; //属性フェッチ,[[Get]]デフォルトの操作:現在の属性を検索し、なければプロトタイプを検索する。
プット操作
obj.a = 3; //代入操作[[Put]]
- getter またはセッター
- writablefalseを指定すると変更できません。
- 代入
getterとsetterは元の[[Get]]と[[Set]]をオーバーライドします。
ゲッター: 値を受け取る関数
var obj = {
log: ['example', 'test'],
get lastest(){ //getメソッドの擬似プロパティ
if(this.log.length === 0){
return undefined;
}
return this.log[this.log.length - 1];
}
}
console.log(obj.lastest); //プロパティにアクセスするには、実際にgetメソッドを呼び出す。
defineProperty、value、writableによるゲッターの定義は機能しません。
var obj = {
get a(){
return 2;
}
}
Object.defineProperty(obj, 'b', {
get: function)() {
return this.a * 2;
}
enumerable: true,
value: 6 //エラー、get操作の重複
writable: true //trueでもfalseでもエラーとなり定義できない。
})
setter: 値を設定する関数
var language = {
set current(name){ //パラメーターを持たなければならない
this.log.push(name)
},
log: []
}
language.current = 'en';
get と set は通常ペアで存在し、get と set の関数名は直接取得できません。
var obj = {
get foo(){
return this._a;
},
set foo(val){
this._a = val * 2;
}
}
obj.foo = 3; //set
console.log(obj.foo); //6
console.log(obj.foo.name); //undefined,名前を取得できない
var descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');
console.log(descriptor.get.name);
console.log(descriptor.set.name);
オブジェクトのシーリング
オブジェクト定数:削除不可、変更不可
Object.definePropertyプロパティ記述子の設定
configurable: false
enumerable: true
value: 2
writable: false
obj.b=3というプロパティを追加。デフォルトではvalue以外の3つの値はすべてtrue。
Object.definePropertyによるプロパティの追加、デフォルトでは3つの値すべてがfalseです。
preventExtensions 展開不可
preventExtensions はプロパティ記述子を変更できません。
isExtensible は、オブジェクトが拡張可能かどうかを判断します。
var obj = {a: 2};
console.log(Object.preventExtensions(obj)); //オブジェクトを返す
obj.b = 3; //サイレントで失敗し、ストリクト・モードでエラーを報告した。
console.log(Object.isExtensible(obj)); //false,展開不可
Object.seal(obj)
sealは設定可能をfalseにします。
isSealed isSealed
var obj = {a: 2};
console.log(Object.seal(obj));
Object.freeze(obj)
freezeはconfigurableとwriteableの両方をfalseにします。これは浅いコピーに過ぎず、深いfreezeを行うには、オブジェクトをループしてメソッドをfreezeする必要があります。
isFrozen isFrozen
function myFreeze(obj) {
Object.freeze(obj);
for(var key in obj) {
if (typeof(obj[key]) !== 'object' && obj[key] !== null) {
myFreeze(obj[key]);
}
}
}
通常、freezeを使用します。
オブジェクト・プロトタイプの他のメソッド
Object.is()すべてが等しいかどうかの判定
'=='は暗黙的に変換します。
'===' は厳密には相対演算子で、基礎となる sameValue アルゴリズムを呼び出します。
2つの値が等しいかどうかを判断するために、ES5では演算子
console.log(NaN === NaN); //false
console.log(+0 === -0); //true
ES6では、'==='を使ってisメソッドを呼び出し、これを決定することができます。
console.log(Object.is(NaN, NaN));
Object.keys()は独自の列挙可能なキーを取得します。
Object.value()は、自身の列挙可能なキー値を取得します。
Object.entriese() は、独自の列挙可能なキーと値を取得します。
プロトタイプのプロパティがなければ
coonst foo = {a: 1};
Object.defineProperties(foo, {
d: {
value: 4,
enumerable: true
},
f: {
value: 5,
enumerable: false
}
})
console.log(Object.keys(foo)); //["a", "d"],f列挙できない
console.log(Object.value(foo)); //[1,4,5]
console.log(Object.entries(foo)); //[["a",1],["d",4]]
渡されたパラメータがオブジェクトでない場合、暗黙的にラッパークラスに変換されます。
let obj = 1;
console.log(Object.keys(obj)); //[]
let obj = 'abc';
console.log(Object.keys(obj)); //["1","2","3"]
Object.assign(tar, ...sourses)マージメソッド
オブジェクトコピー
let obj = {a: {b: 1}};
let tar = {};
let copy = Object.assign(tar, obj); //戻り値は最初のパラメーターである
console.log(copy === tar); //true
console.log(copy === obj); //false
obj.a.b = 2;
console.log(obj.a.b); //2
同じ名前のプロパティの置き換え:
const tar = {a: 1, b: 1};
const tar1 = {b: 2, c: 2};
const tar2 = {c: 3};
Object.assign(tar, tar1, tar2);
console.log(tar); //{a: 1, b: 2, c: 3}後者は前者を上書きする
配列の置換 : 同じ添え字を持つ 2 つの属性が置換されます。
Object.assign([1,2,3],[4,5]);//[4,5,3]
渡された値がオブジェクトでない場合:
Object.assign(undefined, {a: 1});//
var test = Object.assign(1, {a: 1};//ラッパークラスを使ってオブジェクトに変換する
console.log(test); //Number{1, a: 1}
undefined は対応するラッパークラスを持たず、マージできません。
Object.assign({a: 1}, undefined);//{a: 1}
Object.assign({a: 1}, 1);//{a: 1}
Object.assign({a: 1}, true);//{a: 1}
Object.assign({a: 1}, '123');//{0: "1", 1: "2", 2: "3", a: 1}
Object.assign({}, '123', true, 10);//{0: "1", 1: "2", 2: "3"}
第2パラメータがオブジェクトに変換できない場合、処理は行われず、第1パラメータのオブジェクトが返されます。
もし2番目のパラメータがオブジェクトの場合、列挙可能かどうかにも注意してください。
let obj = {a: 1};
Object.defineProperty(obj, 'b', {})
Object.create(proto, [propertiesObject])
第1引数でプロトタイプを指定し、第2引数でプロパティと対応する記述子を設定します。
var obj = Object.create({foo: 1}, {
bar: {
value: 2
},
baz: {
value: 3,
enumerable: true
}
})
console.log(obj); //{baz: 3, bar: 2}
let copy = Object.assign({}}, obj);
console.log(copy); //{baz: 3},となり、fooのプロトタイプはコピーされない。
継承されたプロパティと列挙不可能なプロパティはコピーできません。
symbol() は、完全に異なる、決して複製されない、文字列のようなプリミティブ型を生成します。
では、Symbolはassignでコピーできるのでしょうか? はい、できます。
var test = Object.assign({a: b}, {[Symbol('c')] : 'd'});//{a: 1}
console.log(test)//{a: "b", Symbol(c): "d"}
プロトタイプを展開します:
function Person(){}
var age = 1;
Object.assign(Person.prototype, {
eat(){},
age,
})
オーバーライドの正確な実践
const DEFAULT = {
url: {
host: 'www..com',
port: 7070
}
}
function test(opt){
opt = Object.assign({}, DEFAULT, option);
}
test({url: {port: 8080}})
ユーザーが値を指定していない場合はDEFAULTが使われ、ユーザーが設定した場合はDEFAULTに置き換わります。
値関数をコピーします:
const source = {
get foo(){
return 1;
}
}
const target = {};
Object.assign(target, source); //{foo: 1}
関数本体をコピーする代わりに、特定の値を直接コピーします。
assignが使えない場合は、getOwnPropertyDescriptorを使ってください。
Object.defineProperties(tar, Object.getOwnPropertyDescriptor(source));
console.log(Object.getOwnPropertyDescriptor(tar, 'foo'));
getOwnPropertyDescriptors は浅くコピーするのがとても簡単です。
const clone = Object.create(Object.getPropertyOf(obj), Object.getOwnPropertyDescriptors(obj));
オブジェクトの配置
const obj = {a: 1};
const obj = Object.create(port);
getやsetを使わずにassignを使うことも可能です。
const obj = Object.assign(Object.create(port), {
foo: 123
})
const obj = Object.create(port, Object.getOwnPropertyDescriptors({
foo: 123
}));
プロトタイプ
person.__proto__この方法でプロトタイプにアクセスすることは、非常にパフォーマンスを消費し、プロトタイプを継承するすべてのオブジェクトに影響を与えます。
セマンティクスも良くありません:
Object.setPropertyOf()はプロトタイプを設定または変更します。
Object.getPropertyOf()はプロトタイプを取得します。
Object.create()は、プロトタイプを作成します。
let proto = {
y: 20
}
let obj = {x: 10};
let obj1 = Object.setPropertyOf(obj, proto);
console.log(obj1 === obj); //true 戻り値は最初のパラメーターなので、obj1も使えない。
Object.setPropertyOf(obj, proto);
console.log(obj); //以上だ。
最初のパラメータがオブジェクトでない場合は無効として指定され、undefined/nullの場合はエラーとなります。
let obj = Object.setPropertyOf(1, {a: 1});
console.log(Object.getPropertyOf(obj)); //Number{0}
1最初のクラスは、Numberにクラスをラップすることにより、Numberのプロトタイプであるプロトタイプprintは、失敗を指定します。
オブジェクト.getPropertyOf(1) === Number.prototype
super オブジェクトのプロトタイプを指します。
superキーワードを機能させる唯一の方法は、オブジェクトのメソッドの省略記法として記述することです。
let proto = {
y: 20,
z: 40,
}
let obj = {
x: 10,
foo(){
console.log(super.y)
}
};
Object.setPropertyOf(obj, proto);
obj.foo(); //20
Symbol
ES6で導入された新しいプリミティブ値型で、ES5ではオブジェクトのプロパティの名前を変更するという問題がありました。
Symbolの最初の値は大文字ですが、コンストラクタではないので、括弧に入れても入れなくても同じ意味になります。
括弧をつけなければコンストラクタで、呼び出したければ括弧をつけなければなりません。
var s1 = Symbol;
console.log(s1); //ƒ Symbol() { [native code] }
var s2 = Symbol();
console.log(s1); //Symbol()
そして、このコンストラクタの不思議なところは、新しいコンストラクタを作ることができないということです。
var s1 = new Symbol;
このコンストラクタは一意で、識別子として文字列を渡して区別することができます。
var s1 = Symbol('foo');
var s2 = Symbol('foo');
console.log(s1 == s2); //false
console.log(s1); //Symbol()
console.log(typeof s1); //symbol
s1.a = 1;
console.log(s1.a); //undefined 生の値には属性がない
シンボルの識別子は常に文字列で、undefinedを渡すとそれはなく、nullを渡すと'null'という文字列になります。
明示的な型変換ができないのはNumber型だけです。
var obj = {a: 1};
let s1 = Symbol(obj); //自動的にオブジェクトを呼び出す.prototype.toString()オブジェクトを文字列に変換するメソッド
console.log(s1); //Symbol([Object object])
console.log(s1 + 1); //エラー、s1は暗黙的に数値に変換できない、つまり記号は計算できない。
console.log(String(s1)); //Symbol([object Object])
console.log(s1 + ''); //エラー、文字列型は、パラメータを渡すか、表示するメソッドを呼び出すことによってのみ変換でき、暗黙の変換はできない。
console.log(Boolean(s1)); //true
console.log(!s1); //false,これは暗黙の変換を行う唯一の方法である
console.log(Object.setPropertyOf(s1)); //Symbol,Symbolまた、独自のコンストラクタ
console.log(s1.toString()); //Symbol([object Object])プロトタイプにはtoStringメソッドがある
呼び出し
let name = Symbol();
let person = {};
person.name = 'jackson'; // 一番下の変換者['name']
console.log(person); //{name: 'jackson'}
通常の呼び出しは機能しません。
person[name] = 'jackson';
console.log(person); //{Symbol(): "jackson"}
let name = Symbol();
let eat = Symbol();
let person = {
[name] : 'jackson',
[eat](){
console.log(this[name])
}
}
let name = Symbol();
let person = {};
Object.defineProperty(person, name, {
value: 'jackson'
})
アクセス:.
console.log(person.name);
直接アクセスしても、person['name']に変換されるため動作しません。
次のようにする必要があります。
console.log(person[name]);
person[eat]();
関連するメソッド
メソッドを呼び出すには、コンストラクタの中で呼び出さなければなりません。
Symbol.for()
Symbolが同じ値を得ることはありません。
Symbol.forを使うと、キーとなる値を生成することができます。
var s = Symbol('foo');
var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
console.log(s == s2); //false
console.log(s1 == s2); //true
Symbol.keyFor()
キー値を取得することができます
console.log(Symbol.keyFor(s1)); //foo
console.log(Symbol.keyFor(s)); //undefined
反復: getOwnPropertySymbols
for....in/of... ループはSymbolプロパティをトラバースできません。このための特別なAPIがあります:Object.getOwnPropertySymbols(obj)、このメソッドはSymbolプロパティのみをトラバースします。
const obj = {};
let a = Symbol('a');
let b = Symbol('b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '1';
const objSymbols = Object.getOwnPropertySymbols(obj); //走査された配列を返す
console.log(objSymbols); //[Symbol(a),Symbol(b)]
例
const obj = {c: 1, d: 2};
let a = Symbol('a');
let b = Symbol('b');
let _a = Symbol('_a');
let _b = Symbol('_b');
obj[a] = 'hello';
obj[b] = 'world';
obj.c = '1';
Object.defineProperties(obj, {
e: {
value: 5,
enumerable: true
},
f: {
value: 6,
enumerable: false
},
[_a]: {
value: -1,
enumerable: true
},
[_b]: {
value: -2,
enumerable: false
}
})
let h = Symbol('h');
let i = Symbol('i');
let j = Symbol('j');
const obj1 = {
g: 7,
[h]: 8
}
Object.defineProperties(obj1, {
[i]: {
value: 9,
enumerable: true
},
[j]: {
value: 10
},
k: {
value: 11
}
})
Object.setPrototypeOf(obj, obj1);
console.log(obj);
for(let i in obj){ //自分自身とそのプロトタイプに対して、列挙可能でシンボル以外の属性を反復処理する。
console.log(i);
}
console.log(Object.keys(obj)); //自身の列挙可能な、シンボル以外のプロパティを反復処理する。
console.log(Object.getOwnPropertySymbols(obj)); //列挙可能かどうかにかかわらず、自身のシンボル以外の値を反復する。
var obj3 = {};
Object.assign(obj3, obj); //Copyは、Symbolを含む自身の列挙可能なプロパティだけをコピーする。
console.log(obj3);
繰り返し処理を行うもう一つの方法は、JSON.stringify()で、これは自身の列挙可能なプロパティを繰り返し処理します。
iterator
let arr = [1,2,3,4];
console.log(arr);
arrは、プロトタイプにイテレータインターフェースを展開します Symbol(Symbol.iterator): ƒ values()
コンストラクタ: メソッド
対応するメソッドは arr[Symbol.iterator] から取得できます。
let itar = arr[Symbol.iterator]
console.log(itar); //ƒ values() { [native code] }
let itar = arr[Symbol.iterator]();
console.log(itar);
メソッドを実行すると、プロトタイプの次のメソッドが表示されます。
console.log(itar.next()); //{value: 1, done: false}
valueは読み込んだ値、falseはまだ実行されていないことを意味します。
let arr = [1,2,3,4];
let itar = arr[Symbol.iterator]();
console.log(itar.next());
console.log(itar.next());
console.log(itar.next());
console.log(itar.next());
console.log(itar.next());
console.log(itar.next());
このメソッドを6回連続で実行すると、次のような結果が得られます。
イテレータ: データ構造を読み込む方法、順序付け、連続、データ組織を消費する方法を引っ張ることに基づきます。
イテレータのカプセル化
function makeIterator(array) {
var nextIndex = 0;
return {
next: function() {
return nextIndex < array.length ?
{ value: array[nextIndex++], done: false} :
{value: undefined, done: true};
}
}
}
let itar = makeIterator([5,2,3,4]);
ES6は、c++、java、c#、pythonから、for....の...ループ -> イテレート
for...ループ→反復 for...はイテレータ・インターフェイス
let arr = [1,2,3,4]
for(let i of arr) {
console.log(i); //1,2,3,4
}
for...in...は添え字を取り、オブジェクトを反復処理します。は、値を直接取り、オブジェクトを除き、イテレータ・インターフェイスが展開されているデータ型に対して反復処理します。
オブジェクトを反復処理する場合は、イテレータ・インターフェースを展開する必要があります。
let obj = {
start: [1,2,3,4],
end: [5,6,7],
[Symbol.iterator](){
let index = 0,
arr = [...this.start, ...this.end],
len = arr.length;
return {
next(){
if(index < len) {
return {
value: arr[index++],
done: false
}
}else{
return {
value: undefioned,
done: true
}
}
}
}
}
}
for(let i of obj){
console.log(i);
}
var arr = [6,7,5,1];
var iter = arr[Symbol.iterator]();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
for(let i of arr){ //両方のメソッドを使う場合、for ofは機能しないかもしれない。
console.log(i);
}
...オブジェクトがイテレータ・インターフェースをデプロイしていれば動作しますが、エクステンションをデプロイしていない場合、オブジェクトはエラーを報告します。
let arr = [...obj];
console.log(arr); //[1,2,3,4,5,6,7]
typeArrayはjsには存在せず、バイナリデータに使用されます。
これは型配列であり、クラス配列ではありません。
const tArray = new Int8Array(8); //デフォルトのパディングは8個のゼロ
配列の展開
Array.of()配列の宣言
配列を宣言する際に曖昧さが生じることがありますが、 Array.of()を使用することでこの問題を解決することができます。
console.log(new Array(3)); //[empty x 3]
console.log(Array.of(3)); //[3]
Array.from() 配列の変換
引数: arrayLike, mapFn, this Arg
イテレータ・インターフェースを展開するクラスまたはオブジェクトの配列を配列に変換します。
ES5では配列プロトタイプのsliceメソッドを使用して変換しますが、ES6ではArray.from()を直接使用します。
var oList = document.getElementsByClassName('p');
console.log([].slice.call(oList));
console.log( Array.from(oList));
イテレータ・インターフェースを展開するオブジェクト
console.log(Array.from(obj)); //[1,2,3,4,5,6,7]
console.log(Array.from(obj, function mapper(val, idx){
return val * 2; //[2,4,6,8,10,12,14]
}))
Array.prototype.fill(val, start, end)
元の配列を変更します。startのデフォルトは0からで、endのデフォルトはthis.lengthです。
let arr1 = [1,2,3,4];
let arr = arr1.fill(5);
console.log(arr, arr1); // [5,5,5,5]
間隔 左クローズ 右オープン
let arr1 = [1,2,3,4];
arr1.fill(5, 1, 2);
console.log(arr1); // [1,5,3,4]
startとendが同じ場合は、処理しません。
負の数
arr1.fill(5, -3, -2);
console.log(arr1); // [1,5,3,4]
startで指定された数値が不正な場合、デフォルトの0を使用します。
arr1.fill(5, NaN, -2);
console.log(arr1); // [5,5,3,4]
startとendの両方が不正な場合は何もしません。
また、このメソッドは汎用的であり、オブジェクトに対して強制できることに注意してください。
console.log([].fill.call({lenngth: 3}, 4)); //{0: 4, 1: 4, 2: 4}
長さ3のオブジェクトは4で埋められます。
[].keys()インデックス [].values() [].entries()
Object.keys()/Object.values()/Object.entries()は配列を返します。配列は当然、あらゆる種類のループ、forループ、すべてのforが可能です。
let obj = {a: 1, b: 2};
console.log(Object.keys(obj)); //["a", "b"]
[].keys()/[].values()/[].entries()はイテレータオブジェクトを返します。
let arr = ["a", "b"];
console.log(arr.keys()); //Array Iterator
イテレータなので、nextメソッドやforの
let arr = ["a", "b"];
var iter = arr.keys();
console.log(iter.next());
console.log(iter.next());
console.log(iter.next());
{value: 0, done: false}
{value: 1, done: false}
{value: undefined, done: true}
ループ
for(let i of iter){
console.log(i); //0 1
}
iter には length 属性がないので、通常の for ループは使えません。
オブジェクトにも配列にもこのようなメソッドがありますが、戻り値が異なる点が異なります。
[].copyWithin(target, start, end)
targetは挿入される位置を指し、挿入される値は下2桁で決定され、置換されない値と配列の長さは変更されません。
let arr = [1,2,3,4,5,6,7];
console.log(arr.copyWithin(2)); //[1, 2, 1, 2, 3,4,5]
位置2で、元の配列が開始され、それが一杯になるまで満たされます。
console.log(arr.copyWithin(-2)); //[1, 2, 3, 4, 5, 1, 2]
console.log(arr.copyWithin(0,3)); //[4, 5, 6, 7, 5, 6, 7]
位置 0 で挿入し、3 番目の位置から開始し、4567 個の置換された値で終了し、置換されない値は変更されません。
console.log(arr.copyWithin(0,3,4)); //[4, 2, 3, 4, 5, 6 , 7]
console.log(arr.copyWithin(-2,-3,-1)); //[1,2,3,4,5,5,6]
この属性が使用されることはあまりなく、通常はこの方法の代わりに fill が使用されます。
[].find() / [].findIndex
配列のインデックスを取得するには、indexOfを使用します。
console.log([NaN].indexOf(NaN)); //-1
[NaN].findIndex(y => Object.is(NaN, y)); //0
find()は条件を満たす最初の値を返します。
var arr = [1,2,3,4];
var arr 1 = arr.find(function(value, index, arr) {
return value > 2;
})
console.log(arr1); //3,4がなく、1つの成功が返される
しかし、このメソッドの戻り値は常に値であり、return idx > 2であっても、結果は4であり、戻り値が未定義を見つけることができません。
だから、条件を満たす最初のインデックスを返すためにfindIndexが必要です。
var arr 1 = arr.findIndex(function(value, index, arr) {
return value > 2;
})
console.log(arr1); //2
見つからない場合は-1を返します。
[].includes()
配列が値を含むかどうかを判定
console.log([1,2,NaN].includes(NaN)); //true
値の展開
ES5 の 16 進表現: 値の前に 0x をつけます。
大文字と小文字を区別しない2進数と8進数の表現が追加されました。
10進数から2進数へ
Number.prototype.toString.call(502, 2);
2進数から10進数
parseInt(111110111, 2);
ES6では、このような面倒なことをしなくても、0b + 変換したい2進数だけで変換できます。
0b111110111既存のメソッドポイントの調整
ES6では数値に関するメソッドはグローバルではなくNumberコンストラクタに置かれます。
- isNaN()
- isFinite()[制限されているかどうかの判断]
そして、isNaN()とisFinite()に手を加えました:
グローバルな isNaN() は、暗黙の変換を行います。
console.log(isNaN("NaN")); //true
微調整後の isNaN() は
console.log(Number(isNaN("NaN"))); //false
isFinite() も同様で、グローバルに文字列が渡されると、暗黙的に変換されます。
新しいメソッド
- 整数かどうかを判定する Number.isInteger(): 24.0 も整数です。
- Number.MAX_SAFE_INTEGER最大安全整数: 整数処理の上限、すべて Math.pow(2, 53) - 1 に等しくなります。
- Number.MIM_SAFE_INTEGER === -Math.pow(2, 53) + 1
- Number.isSafeInteger()安全な整数かどうか
正規展開
- 正規変形
ES5
var reg = new RegExp('xyz', 'i');
var reg = new RegExp(/xyz/i);
var reg = /xyz/i;
ES6
var reg = new RegExp(/xyz/gi, 'm'); //この場合、1つのパラメーターの修飾子は無効になり、後続のパラメーターが優先される。
- 文字列の正規メソッドの調整
以下のメソッドは、通常のプロトタイプで使用できます:
これらは文字列のメソッドと同じですが、元々はStringプロトタイプで書かれていたものをES6でregularプロトタイプに適応させたものです。
String.prototype.match -> RegExp.prototype[Symbol.match]
- 新しい修飾子 u y s
| y | sticky sticky, 連続した文字にマッチします。 |
| u | Unicodeエンコーディングにマッチ |
| s | dotAllは.ですべてを表します。 |
y
修飾子は通常のプロパティに対応します
var reg = new RegExp('xyz', 'ig');
console.log(reg.global); //true
var str = 'aaa_aa_a';
var reg1 = /a+/g;
var reg2 = /a+/y;
console.log(reg1.exec(str));
console.log(reg2.exec(str)); //の3つのaにマッチする。
console.log(reg1.exec(str)); //を2つにマッチさせる。
console.log(reg2.exec(str)); //null,aaa_aa真ん中は連続していないので、マッチしない
g と y のどちらか一方だけがマッチする場合は、違いはありません。
u
jsはUTF-16、U+0000からU+FFFFの範囲の一般的な文字のための16進ユニコードエンコーディングを使用します。
上記の範囲の一部の漢字を表現することができません。例えば、5ビットコードポイント表現である「⊖u20bb7」のような状況が発生する可能性がありますが、ブラウザが認識できないため、4バイトにする必要があります。
U+D800からU+DFFFの範囲では、正常な部分を超えています。
ES5では、以下は誤りで、実際には、ⒶuD83DとⒷuD83DⒷuDC2Aは全く同じものではありません。
console.log(/^\uD83D/.test('\uD83D\uDC2A')); //true
ES6はこの欠点を修正しました。
console.log(/^\uD83D/u.test('\uD83D\uDC2A')); //false
エンコーディングがU+0000からU+FFFFの範囲を超えると、マッチできる物理的な限界を超えてしまいます。アクセスできません。
var s = '\uD83D\uDC2A';
console.log(/^.$/.test(s)); //false
console.log(/^.$/u.test(s)); //true
さらにES6では、{}が追加され、5ビットのコードポイント表現を認識できるように最適化されています。
console.log('\u{20bb7}')
括弧の中に2桁だけ書いても自動的に補完されます。
console.log('\u{0041}\u{0042}\u{0043}'); //ABC
console.log('\u{41}\u{42}\u{43}'); //ABC
s
..nと.rは一致しないので、s修飾子をつけて.nと.rを一致させます。そうすれば、本当にすべての意味になります!
console.log(/foo.bar/.test('foo
bar')); //s
console.log(/foo.bar/s.test('foo
bar')); //s
source はルールの本体を返し、flags はすべての修飾子を返します。
var reg = /\wabc/giy;
console.log(reg.source); // /\wabc/
console.log(reg.flags); //giy
文字列メソッド
codePointAt()
var s = '\u{20bb7}';
console.log(s.length); //2
jsの内部エンコーディングはUTF-16なので、ⅹu{20bb7}はⅹuD842uDC2Aに変換され、ⅹuxxxxは1文字を表すので、合計2バイトになります。
ES5はcharAtでインデックスに対応する文字を出力します。
console.log(s.charAt(0)); //
console.log(s.charAt(1)); //
ES5ではcharAtでインデックスに対応する文字を出力します。
charCodeAtは、0進数コードポイントの文字に対応するインデックスを出力します。
console.log(s.charCodeAt(0)); //55362 10進数のコードポイントを返す
console.log(s.charCodeAt(1)); //57271
バイナリに変換
console.log(Number.prototype.toString.call(55362, 16)); //d842
console.log(Number.prototype.toString.call(57271, 16)); //dfb7
ES5のこの処理は理想的ではなく、文字が通常の範囲外の場合はうまく動作しません。
ES6 codePointAt
var s = '𠮷a';
console.log(s.codePointAt(0)); //134071,\u20bb7
console.log(Number.prototype.toString.call(134071, 16)); //20bb7
console.log(s.codePointAt(1)); //57271,\uDC2A
console.log(s.codePointAt(2)); //91,a
console.log(s.length); //3
このメソッドは、どんなに長い文字であっても、ビット0の文字全体のエンコーディングを解析します。
文字の長さが4バイトの場合、1バイトは8ビットを占有します。
function is32Bit(c){
return c.codePointAt(0) > 0xFFFF;
}
console.log(is32Bit('𠮷')); //true
codePointAt メソッドは16進数値と直接比較できる値を返します。16進数値を直接出力すると、コンソールに16進数値が出力されるので、すべて16進数になっているので、お互いに比較できます。
String.fromCodePoint
コードポイントを渡し、その文字を返します。
fromCharCodeを使用、通常の範囲外では文字化けします。
console.log(String.fromCharCode(0x20bb7)); //
console.log(String.fromCharCode(0x20bb7) === String.fromCharCode(0x0bb7));
この場合の処理方法は、最上位ビット'2'を破棄することです。
String.fromCodePointにはこの問題はありません。
console.log(String.fromCodePoint(0x20bb7)); //𠮷
イテレータ
文字列プロトタイプにはSymbolのイテレータ・インターフェースがあり、これは
文字列プロトタイプにイテレータがあるので、文字を取り出すことができます。
for(let value of s){
console.log(value); //
}
for ofは文字数制限を超えた値を扱うことができます。
let str = String.fromCodePoint(0x20bb7);
for(let i = 0; i < str.length; i++){
console.log(str[i]); //2つのちんぷんかんぷん
}
for(let i of str){
console.log(i); //𠮷
}
includes(), startWith(), endWith()
これらのメソッドの条件下で特定の文字が含まれるかどうかを示すブール値を返します。
let s = "hello world!";
console.log(s.startWith("hello"));
console.log(s.endWith("!"));
console.log(s.includes("o"));
repeat()
元の文字列をn回繰り返します。小数がある場合は小数を捨てます。
console.log("x".repeat(3)); //xxx
console.log("x".repeat('3')); //xxx
console.log("x".repeat(3.9)); //xxx
console.log("x".repeat(NaN)); //
console.log("x".repeat(0)); //
padStart() padEnd()
console.log("x".padStart(5, "ab")); //ababx
パディング後のビット数は5
console.log("x".padStart(4, "ab")); //abax
console.log("x".padEnd(5, "ab")); //xabab
テンプレート文字列
目的を達成するために、正規置換テンプレートを使用します。
テンプレート文字列の基本的な使い方
let name = 'web';
let info = 'developer';
let m = `I am a ${name} ${info}`; //I am a web developer
これは文字列スプライシングの手法です
let m = 'I am a ' + name + '' + info;
また、{}の中は式であり、評価されてメソッドに渡されることに注意してください。
let x = 1;
let y = 2;
console.log(`${x} + ${y} = ${x + y}`); //1 + 2 = 3
let obj = {x: 1, y: 2};
console.log(`${obj.x} + ${obj.y} = ${obj.x + obj.y}`);//1 + 2 = 3
function fn(){
return 'hello world';
}
console.log(`function result ${fn()}`); //function result hello world
関数の実行によって返される結果はすべて文字列に変換されます。
function fn(){
return [1,2,3,4];
}
console.log(`function result ${fn()}`); //function result 1,2,3,4
文字列とテンプレートの入れ子
let msg = `hello, ${'place'}`;
console.log(msg); //hello, place
テンプレートのレンダリング
const temp = arr1 => `
<table>
${
arr1.map( addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`)
}
</table>
`;
const data = [ {first: 'tanaka', last: 'san'}, {first: 'li', last: 'si'}];
console.log(temp(data));
コンソール印刷
<table>
<tr><td>tanaka</td></tr>
<tr><td>san</td></tr>
,
<tr><td>li</td></tr>
<tr><td>si</td></tr>
</table>
カンマを返すのは、map メソッドが配列も返すためで、カンマで文字列に変換されます。
const temp = arr1 => `
<table>
${
arr1.map( addr => `
<tr><td>${addr.first}</td></tr>
<tr><td>${addr.last}</td></tr>
`).join('')
}
</table>
`;
map メソッドの後に jion メソッドを追加して、カンマがないように null で連結します。
const data = [
{first: 'tanaka', last: '<script>alert('abc')</script>'},
{first: 'li', last: 'si'}
];
タグテンプレートが表示され、タグテンプレートはテンプレート文字列内の変数を取得できます。
let x = 1;
let y = 2;
console.log(`hello ${x + y} world ${x * y}`);
tag`hello ${x + y} world ${x * y}`
タグテンプレートの実行、これはタグを実行する関数と同じです。
関数の戻り値を定義することができます。
function tag($, $1, $2){
console.log($, $1, $2)
}
コンソール印刷
対応する式の結果を、変数をセパレータとして、文字列を区切って配列にしたもの。
これにより、入力されるデータ変数を制御することができます。





