コード日進月歩

しんくうの技術的な小話、メモ、つれづれ、など

JavaScriptのDestructuring(分割代入)に関してざっくりまとめる

便利だけど名前がふわっとしているので雑にまとめる

今回取り上げるもの

JavaScriptにおいて Destructuring assignment と呼ばれるもの、日本語では分割代入と訳したり、ままカタカナ語でデストラクチャリングという。大きくこの機能には「配列を対象にしたもの」「オブジェクトを対象にしたもの」が存在するのでその2つのくくりで説明をする。

配列

配列を分割して代入をすることができる

const baseArray = [1,2,3]

const [frist,sencond,third] = baseArray
// firstには1 , secondには2 , thirdには3が入る

また、部分的に取り出したりすることもできる

const baseArray = [1,2,3]

const [ichi] = baseArray
// ichiに1が入る

const [x,,z] = baseArray
// xに1 , zに3が入る

またスプレッド構文を用いた残余引数(RestParameter)を指定すると広域に切り取りができる

const longArray = [10,20,30,40,50]

const [ichi,...nokori] = longArray
console.log(ichi) // 10
console.log(nokori) // [20,30.40.50]

ただし残余引数のあとに別の変数を設定を指定していれることはできない

// 下記のような記述をするとエラー
const [first,...aida,last] = longArray

引数への活用

関数の引数に使うこともできる

function loggingfirst([first, ...nokori]){
  console.log(`logging ${first}`)
}

let array = [2,4,8,16]
loggingfirst(array) // logging 2

オブジェクト

オブジェクトは対応するキーのものがあれば入る形になる

let source = { age: 20, name: "Tanaka", country: "Japan"}
let {name , age} = source

console.log(name) // Tanaka
console.log(age) // 20

もちろん対応するオブジェクトがない場合は入らない

let source = { age: 20, name: "Tanaka", country: "Japan"}
let {test , age} = source

console.log(test) // undefined
console.log(age) // 20

また初期値設定もできる

let source = { age: 20, name: "Tanaka", country: "Japan"}
let {test = "test text" , age = 30} = source

console.log(test) // test text
console.log(age) // 20

キー名とは異なる変数への割当

以下のように書くことでキー名と別の変数に割り当てることができる

let source = { age: 20, name: "Tanaka", country: "Japan"}
let {test: newTest = "test string" , age: newAge , todouhuken: region} = source

console.log(newAge) // 20
console.log(newTest) // test string
console.log(region) // undefined

この構文はコロンを挟んで右側に要素を入れる形なので気をつける。(だいたい他の構文はコロンの左側に右側の値を入れる)

引数への活用

配列同様に引数にも活用できる

function loggingName({name}){
  console.log(`logging ${name}`)
}

let source = { age: 20, name: "Tanaka", country: "Japan"}
loggingName(source) // logging Tanaka

参考リンク

JavaScriptのスプレッド構文(...)についてざっとまとめる

ドットドットドットとかトリプルドットとか、ググる場合の初見殺しであるスプレッド構文に関してまとめる

スプレッド構文とは

変数名の前にドット3つで表現する構文 ... というものをスプレッド構文という。なお、functionの引数に...を付けて表現するものは残余引数なので、それは後述。

使い方

配列のコピー

配列を複製するのに使うことができる。JSで変数を扱う場合イミュータブルにしたいケースが多いので、配列操作をするときに重宝する。

let target = [1,2,3]
// [1, 2, 3]
let new_array = [...target,10]
// [1, 2, 3, 10]
let long_array = [100,...new_array,1000]
// [100, 1, 2, 3, 10, 1000]

ただし、多次元配列には適さないので注意。

オブジェクトのコピー、改変

スプレッド演算子を使うとオブジェクトの値として代入が可能。いろいろなパターンの応用ができる。

純粋に複製する

let obj = { name: "taro" , age: 20 }
// {name: 'taro', age: 20}

let copy_obj = {...obj}
// {name: 'taro', age: 20}

キーと値を追加する

let obj = { name: "taro" , age: 20 }
// {name: 'taro', age: 20}

let new_obj = { ...obj, skill: "運転免許" } 
// {name: 'taro', age: 20, skill: '運転免許'}

こちらに関しては変数名だけ書くとその変数のキーの値を入れるということもできる。設定したキー名と変数名が一致した場合は後述の上書きの挙動とおなじになる。

let obj = { name: "taro" , age: 20 }
// {name: 'taro', age: 20}

let power = 20
let power_obj = {...obj , power} 
// {name: 'taro', age: 20, power: 20}

既存要素を上書きする

let obj = { name: "taro" , age: 20 }
// {name: 'taro', age: 20}

let ziro_obj = { ...obj, name: "jiro" }
// {name: 'jiro', age: 20}

let age = 35
let feature_obj = { ...obj , age}
// {name: 'taro', age: 35}

残余引数とは

functionの引数に...を3つつけることで実現する数に縛られない引数。いわゆる可変長引数。下記の moreArgs のように記述する。

function test(mustArg1, mustArg2, ...moreArgs) {
  console.log("Arg1 is ", mustArg1)
  console.log("Arg2 is ", mustArg2)
  console.log("moreArgs is ", moreArgs)
}

上記のfunctionを利用すると以下のようになる。

// 引数として指定しないと空の配列となる

test("1" , "2")
// Arg1 is  1
// Arg2 is  2
// moreArgs is  []
// 複数指定するとその分配列で値が入る

test("1" , "2" , "3" , "4")
// Arg1 is  1
// Arg2 is  2
// moreArgs is  (2)['3', '4']

ちなみに残余引数のあとに、通常の引数を記述することはできない

// 下記のように定義するとエラーになる

function test(firstArg , ...args , lastArg){
}

参考リンク

GoogleAppScriptでJSを使う場合、便利なメソッドが用意されている

base64変換処理とかECMA2015の標準にないからつくらないといけないのかな…とか思ったときに

リファレンス

Class Utilities | Apps Script | Google Developers

どんなものがあるか

  • BASE64への変換/BASE64からの復元(base64Encode/base64Decode)
  • ByteデータからBlobへの変換(newBlob)
  • CSVやTSVをString配列に変換(parseCsv)
  • gzip形式への圧縮/解凍(gzip/ungzip)
  • Date型を文字列変換(formatDate)

参考リンク

アスタリスクを2つ並べる記法(**)をglobstar(グロブスター)と表現することがある

ググりにくいんだけど、あんまり呼称が定着指定ない感じもしたので調べてみた

TL;DR

ディレクトリパスの指定などで ** と書くことがあり、その際の呼称を globstar と記載することがある。なお globstar という呼称で呼ばれるのはbashのオプション名が起源かと思われる。

**が登場するドキュメント

Docker

Dockerの設定としても登場する。

Go 言語の filepath.Match ルールを拡張し、 Docker は特別なワイルドカード文字列 ** もサポートします。これは、(0も含む)複数のディレクトリに一致します。 - Dockerfile リファレンス — Docker-docs-ja 20.10 ドキュメント

GitHub Actions

GitHub Actionsでフィルタパターンとして登場している

ゼロ個以上のキャラクタにマッチしますが、/にはマッチしません。 たとえばOctoはOctocatにマッチします。
・** ゼロ個以上の任意のキャラクタにマッチします。
- GitHub Actionsのワークフロー構文 - GitHub Docs

そもそもglobとは

wikipediaの記述が的確なので転載する。

グロブ(英: glob)とは主にUnix系環境において、ワイルドカードでファイル名のセットを指定するパターンのことである。例えば、UNIXのコマンド「mv .xlsx 営業実績/」はカレントディレクトリから営業実績/ディレクトリへと.xlsxで終わる全てのファイルを移動する。ここで、は「任意の文字列」を表すワイルドカードであり、.xlsxはグロブである。以外に一般的なワイルドカードは疑問符 (?) であり、これは任意の1文字を表す。 - グロブ - Wikipedia

このようにワイルドカードとセットで表現した文字列のことをグロブという。

globstarという呼び方の由来について

紹介したドキュメントで ** という記法は登場するが、大体記号を記載することで説明としては完結するので、ドキュメント上は「globstar(グロブスター)」という表現は登場しない。

そのため明示的に「globstar(グロブスター)」という呼称を使っているものはどこが起源かというところが見当たらないので、少し調べてみた。

** という記法の起源

下記のブログ曰く、 ** という記法は、zshが起源ではないかとされている。

そしてついに Zsh-2.2 の Modification history に、 **/ が出現します。 (中略) 時に、1992/05/14。 ここまでの経緯を見るに、zsh が元祖ではないか?と私には見えました。 -再帰globパターン **/ の元祖は zsh なのか、調べてみた - hkoba blog

しかしながらzshのドキュメントにはglobstarという表現は見当たらない、そこでもう少し追う。

bashでの利用とオプション名としての命名

この **bashで利用したい場合 globstar という名前でオプション指定できるようになっている。

シェル変数「globstar」を有効にすると、「**」によるパス名展開を使用できるようになります。 - 【 shopt 】コマンド(応用編その5)――「**」によるパス名展開を可能にする:Linux基本コマンドTips(366) - @IT

このglobstarオプション自体が(bashに加わったのはversion4で、時系列としては2005年あたりになるが、ざっくり調べて見たがこれ以外にglobstarという表現を使っているケースが無く、おそらくこのbashのオプション表現が呼び名としての起源かと推察される。

参考リンク

認証と認可がわからなくなったとき、誰かに教えるときに起点にしたい記事「よくわかる認証と認可」

複数サービスをまたぐログイン機構をやる瞬間が多いので、基本を振り返るためのものとして。スライドではないけど回顧録として。

対象の記事

dev.classmethod.jp

みどころ

  • 混同されがちな「認証」と「認可」を短い文章でたとえを交えながら説明された文章
  • TwitterFacebookOAuth認証を使ってログインをする機構を作ることが多いが、本質的なことをわからなくても実装できてしまうため、なんとなく作ってしまった人が読むといい記事。
  • また、改めてログイン機構などをつくるさいに学び直しの起点として読み直すと頭が整理される。

関連リンク

Plain Old *** Object の語源を調べる

POJOとかPOROとか言うけど、何がこの言い回しの由来なのか調べる。

そもそもPlain Oldとは

英語の直訳的な意味としては「単純な」や「普通の」という意味にあたる。なおPlaneではなくPlain。

初出はPlain Old Java Object

初めて Plain Old の言い回しが使われはじめたのは2000年ごろとされている。具体的に使い始められたのは以下のリンク先の文章に記述がある。

この言葉は、2000年9月にRebecca Parsons、Josh MacKenzie、私の3人があるカンファレンスでの講演を準備していたときに生まれたものです。- POJO

使われ始めた背景

先ほどの文章に使い始めた理由が述べられており

私たちは、なぜ人々が自分のシステムで通常のオブジェクトを使うことに反対するのか不思議に思い、単純なオブジェクトには洒落た名前がないからだと結論づけました。そこで、私たちはこの名前をつけました。そして、この名前はとてもうまく受け入れられました。

このように普通のオブジェクトにあたるものの名前がなかったので、名前を与えたという話になる。

派生の言葉

派生の言葉としては色々あり以下のような言葉がある

  • Plain Old Ruby Object
  • Plain Old PHP Object
  • Plain Old CLR Object
  • Plain Old Telephone Service
  • Plain Old Documentation

関連リンク

Rubyにてyield_self/thenを使って普通の戻り値をメソッドチェインのように使う

このエントリはRubyのAdventCalendar2021の13日目の記事です。

書き方として割と見かける事が多いので、こういう使い方もできるよという知識の一つとしてご紹介します。

環境

$ ruby -v
ruby 3.0.1p64 (2021-04-05 revision 0fb782ee38) [x86_64-darwin19]

今回取り上げるメソッド

Object#then (Ruby 3.0.0 リファレンスマニュアル)

リファレンスとしては then で紹介されているが yield_selfエイリアスとなっている。

どういうときに使えるか

例えば 「対象の変数」の数値に2を加算した数をした数を用意し、その数をその数の分だけ掛け算し、結果の内容を文字列にしたい場合

# 対象の変数はtarget
target = 2

target_plus_two = target + 2
result = (target_plus_two ** target_plus_two).to_s

このようにかけるが変数代入が大変なので、これがyield_selfを使うと以下のように記述できる

target = 2

target.yield_self{|x| x + 2}.yield_self{|x| x ** x}.to_s

使える場面

例えば https://httpbin.org/json にリクエストをすると以下のようなJSONが返ってくる。

{
  "slideshow": {
    "author": "Yours Truly",
    "date": "date of publication",
    "slides": [
      {
        "title": "Wake up to WonderWidgets!",
        "type": "all"
      },
      {
        "items": [
          "Why <em>WonderWidgets</em> are great",
          "Who <em>buys</em> WonderWidgets"
        ],
        "title": "Overview",
        "type": "all"
      }
    ],
    "title": "Sample Slide Show"
  }
}

その際に取得したJSONslideshow.authorという階層の中身を取り、"slide author is #{slideshow.author}" とやりたい場合に愚直に書くと以下のようになる。

require 'open-uri'
require 'json'

url = "https://httpbin.org/json"

response = URI(url).read
parse_hash = JSON.parse(response)
p "slide author is #{parse_hash.dig('slideshow','author')}"

ただ、ここを yield_self/then を使うと以下のようにメソッドチェイン風に書くことができる

require 'open-uri'
require 'json'

url = "https://httpbin.org/json"

URI(url)
  .read
  .then{|response| JSON.parse(response)}
  .dig('slideshow','author')
  .then{|pick_author| p "slide author is #{pick_author}" }

参考サイト