// function
const plusOne = function(n){
return n + 1;
}
// アロー関数
const addOne = (n) => {
return n + 1;
};
// アロー関数(省略記法)
// 本文がreturn文だけのときは、return文をブロックごと省略できる
const increment = n => n + 1;
console.log(plusOne(1));
console.log(addOne(1));
console.log(increment(1));
// デフォルト引数
const raise = (n, m=2) => n ** m;
console.log(raise(2, 3)); //8
console.log(raise(3)); //9
// Rest parameters
// 最後の引数の前に, 「...」プレフィックスをつけることで、残りの引数を配列として受け取れる
const showNames = (a, b, ...rest) => {
console.log(a);
console.log(b);
console.log(rest);
};
showNames('John', 'Jane', 'Johnny', 'Jenny', 'Julia');
// 引数の1つ目でもrest parametersは使用可能
const showAllArgs = (...args) => {
console.log(args);
};
showAllArgs('A', 'B', 'C', 'D');
// rest parametersに名前をつけて取得できる。ただし、定義以上の数の引数は捨てられる
const sum = (i, ...[j, k, l]) => i + j + k + l;
console.log(sum(1, 2, 3, 4)); //10
console.log(sum(1, 1, 1, 1, 1)); //4
// オブジェクトのキーや値を変数から取得する
const key = 'bar';
const baz = 65536;
const obj1 = {foo: 256, [key]: 4096, baz: baz};
console.log(obj1); //{foo: 256, bar: 4096, baz: 65536};
// プロパティのショートハンド
const obj2 = { baz };
console.log(obj2); //{baz: 65536}
// 分割代入
const [n, m] = [1, 4];
console.log(n, m); //1 4
const obj = {name: 'Kanae', age: 24};
const { name, age } = obj;
console.log(name, age); //Kanae 24
// 分割代入2
// オブジェクトのプロパティのキー名を指定して分割代入する
const response = {
data: [
{
id: 1,
name: 'Patty Rabbit',
email: 'patty@maple.town',
},
{
id: 2,
name: 'Rolley Cocker',
email: 'rolley@palm.town',
},
{
id: 3,
name: 'Bobby Bear',
email: 'bobby@maple.town',
},
],
};
const { data: users = [] } = response; // キー名がなかったときに備えて[]をデフォルト設定
console.log(users);
//[
// { id: 1, name: 'Patty Rabbit', email: 'patty@maple.town' },
// { id: 2, name: 'Rolley Cocker', email: 'rolley@palm.town' },
// { id: 3, name: 'Bobby Bear', email: 'bobby@maple.town' }
//]
// スプレッド構文
// 配列やオブジェクトの前に...をつけることで中身を展開する
// Rest parametersとやってることは同じ
const arr1 = ['A', 'B', 'C'];
const arr2 = [...arr1, 'D', 'E'];
console.log(arr2); //[['A', 'B', 'C', 'D', 'E']
const obj1 = { a: 1, b: 2, c: 3, d: 4 };
const obj2 = { ...obj1, d: 99, e: 5 }; //同じキーのものは上書きされる
console.log(obj2); //{ a: 1, b: 2, c: 3, d: 99, e: 5 }
const user = {
id: 1,
name: 'Patty Rabbit',
email: 'patty@maple.town',
age: 8,
};
const { id, ...userWithoutId } = user;
console.log(id, userWithoutId);
// 1 { name: 'Patty Rabbit', email: 'patty@maple.town', age: 8 }
オブジェクト型の値は変数に代入しただけだと、参照渡しになり実態は共有されたままので、コピーするときには別の方法を考える必要がある
const original = { a: 1, b: 2, c: 3 };
const copy = { ...original }; // オブジェクトのコピーにスプレッド構文を使う
console.log(copy);
console.log(copy === original); // false プロパティは同じでもアドレスの違う別物
const assigned = { ...original, ...{ c: 10, d: 50}, d: 100 };
console.log(assigned); // { a: 1, b: 2, c: 10 , d: 100}
console.log(original); // { a: 1, b: 2, c: 3 }
上記はシャローコピー(コピーされるオブジェクトの深さが1段階までしか有効でない)ので、プロパティの値がさらに配列やオブジェクトでネストされている場合はそれらの値はコピーしない
const patty = {
name: 'Patty Rabbit',
email: 'patty@maple.town',
address: { town: 'Maple Town' },
};
const rolley = { ...patty, name: 'Rolley Cocker' };
rolley.email = 'rolley@palm.town';
rolley.address.town = 'Palm Town';
console.log(patty);
// {
// name: 'Patty Rabbit',
// email: 'patty@maple.town',
// address: { town: 'Palm Town' }
// }
// addressはオブジェクトなので、参照がコピーされているだけとなる。
// 一旦文字列として展開して、JSONパースするという技もあるが、
// プロパティにDateオブジェクトや、関数、undefinedが入ってるとうまくいかない
// コピーしてプロパティを書き換えるという場面があまりないので、
// 基本はシャローコピーをしつつどういう危険性があるかを認識しておく
// &&や||を使って右辺の評価を左辺の評価に委ねる
// ||は左辺がfalsyな値だと右辺に渡される
// &&は左辺がtruthyな値だと右辺に渡される
const hello = undefined || null || 0 || NaN || '' || 'Hello!';
const chao = ' ' && 100 && [] && {} && 'Chao!';
true && console.log('1.', hello); // 1. Hello!
false && console.log('2.', hello); //
true || console.log('3.', chao); //
false || console.log('4.', chao); // 4. Chao!
const users = [
{
name: 'Patty Rabbit',
address: {
town: 'Maple Town',
},
},
{
name: 'Rolley Cocker',
address: {},
},
null,
];
for (u of users) {
const user = u ?? { name: '(Somebody)' };
const town = user?.address?.town ?? '(Somebody)';
console.log(`${user.name} lives in ${town}`);
}
// ??(Nullish Coalescing) はSQLでいうところのcoalesceと同じ。左辺がNULLかundefinedのときに右辺にいく
// ?.(Optional Chainning)使うと、各階層でプロパティがなくtype errorが発生してもundefinedで返ってくる
const dump = function(){ console.log('`this` is', this); };
const obj = new dump();
//`this` is dump {}
obj !== dump.prototype
//true
const foo = {
name: 'Foo Object',
dump() {
console.log(this);
},
};
foo.dump(); // { name: 'Foo Object', dump: [Function: dump] }
JavaScriptでは、thisが実際にはグローバル変数である。メソッドではない関数、およびnew演算子をつけずに実行される関数は、グローバルオブジェクトがthisとして引き渡される。
const Person = function(name) { this.name = name; return this; };
Person('somebody');
<ref *1> Object [global] {
global: [Circular *1],
clearInterval: [Function: clearInterval],
clearTimeout: [Function: clearTimeout],
setInterval: [Function: setInterval],
setTimeout: [Function: setTimeout] {
[Symbol(nodejs.util.promisify.custom)]: [Getter]
},
︙
},
name: 'somebody'
}
> name
'somebody'
// グローバル汚染が起きる
// use strict をファイルの先頭行や関数の最初につけることで、これは防止できる
const Person = function(name) { 'use strict'; this.name = name; return this; };
Person('somebody');
Uncaught TypeError: Cannot set properties of undefined (setting 'name')
at Person (REPL1:1:57)
//call や applyを使うとオブジェクトを指定することができる
function test() {
console.log(this)
}
var obj = { name: "obj" }
test() // => Window {frames: Window, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}
test.call(obj) // => {name: "obj"}
test.call(obj)はobj.test()に等しい(ただし、この例ではobjにtestのメソッドは追加されない)
var obj = new function() {
this.name = "obj"
console.log(this) // => {name: "obj"}
}
// new を使うと、新規にオブジェクトを作成して、それに対して、
// call を使って function を呼び出して、関数内部で return this するような動作になります。
// 上記は以下と同じ動作
var obj = function() {
this.name = "obj"
console.log(this) // => {name: "obj"}
return this
}.call({})
// 強制的にオブジェクトを結びつける
function test() {
console.log(this)
}
var obj = { name: "obj" }
var check = test.bind(obj)
check() // => {name: "obj"}
// check呼び出しには.がついてないがobjがbindされているので、this=objとなる
import { ONE, TWO as ZWEI } from './constants.js';
export const plus = (n, m = ONE) => n + m;
const times = (n, m = ZWEI) => n * m;
// デフォルトエクスポート。名前なしエクスポートで、名前は読み込む側で任意設定
// デフォルトエクスポートは1モジュール(1ファイル)につき1回まで
export default times;