※スマホ察応はしおたせん。

JPEG/Exif画像の回転情報を取れるや぀䜜った。

カテゎリヌ: JavaScript

新幎明けたしおおめでずうございたす。䜜ったよ。

むンストヌル。

$ npm install @ginpei/exif-orientation

利甚䟋。

import * as exif from '@ginpei/exif-orientation';
 
const orientation = await exif.getOrientation(fileOrBuffer);
console.log(
  `${orientation.rotation} degree,`,
  orientation.flipped ? 'flipped' : 'not flipped',
);

䞊蚘のものではないが実行䟋。

$ node from-node.js sample-images/090-flipped-5.jpg
Read image from: sample-images/090-flipped-5.jpg
Rotation: 90 degree, Flipped: true.

怜玢するずいかにもな名前のや぀ずかが耇数出おくるんだけど、先行事䟋に察する利点は特にないです、たぶん。

䜜りたいので䜜った感じのや぀です。ちゃんず動くず思うけど。

Scoped package

名前が取られおたけど䜜っちゃったし倉えるのもなあず思っお、自分の名前 “@ginpei” 付きの圢での公開ずしたした。

READMEにも曞いたけど、TypeScriptの堎合は --moduleResolution node の蚭定が必芁です。ぞえそうなんだ、知らなかった。

゚ラヌ䟋。

src/index.ts:1:23 - error TS2307: Cannot find module '@ginpei/exif-orientation'.

1 import * as exif from '@ginpei/exif-orientation';
                        ~~~~~~~~~~~~~~~~~~~~~~~~~~


Found 1 error.

Exif仕様

こちらのPDFを倧いに参考にしおいたす。感謝感謝。

ずころでExifお日本発祥の芏栌なんだね。

富士フむルムが開発し、圓時の日本電子工業振興協䌚 (JEIDA)で芏栌化

画像の回転

ずかそういうのは、䞀切しないです。調査するたで。

やるならCanvasが良いのかな。いやJPEGの画玠情報の䜍眮を回転的に動かす方が再圧瞮しないから綺麗そう。

䞀時的ならCSSでやるのも手。よし transform: matrix() 䜿おうぜ

JPEG以倖

Exifを他の芏栌の画像にも䜿えるらしいんだけど、JPEGのみの察応です。芋ないし。

おしたい

本幎もよろしくお願い臎したす。

2018幎を振り返る。

カテゎリヌ: 日蚘

日蚘です。

たずめ

がちがち䜜ったなヌ。

GitHub

GitHubプロフィヌルペヌゞのContributionsのキャプチャ。がちがち草生えおる。
GitHubの1幎分の掻動結果。

自分のGitHubプロフィヌルペヌゞで2018幎を開いお、これする。

(() => {
  const year = 2018;
  const days = [...document.querySelectorAll('rect.day')]
    .filter(e=>e.getAttribute('data-date').startsWith(year));
  const counts = days.map(e=>e.getAttribute('data-count')|0);
  const sum = counts.reduce((s,c)=>s+c);
  console.log(`${year}幎${days.length}日䞭掻動したのが${counts.filter(v=>v!=0).length}日、合蚈${sum}回、平均${(sum/days.length).toFixed(2)}回毎日。`);
})();

2018幎365日䞭掻動したのが196日、合蚈1466回、平均4.02回毎日。

䜜ったもの

Clock

1月。アナログ時蚈 + ポモドヌロタむマヌ。

手頃に䜿えるアナログ時蚈が欲しいなず思っお、PCの脇にスマホを立おおそっちに映す甚に。

どうせならブラりザヌじゃなくおも動くようにしようかなず思っお、埌述のQuick NoteでPWAを詊しお、その埌導入した。結果的にNuxt.jsがよしなにやっおくれるのであたり気にする必芁はなかったけど。

そう、Nuxt.js䜿ったけどあんたり䟿利機胜䜿っおなかった。History APIを䜿うSPAもGitHub Pagesだず䜿えないし。

Quick Note

2月。オフラむンでも動く簡単ノヌト。入力内容はLocalStoragに保存される。

PWAを䜜っおみたいず思っお䜜ったや぀です。䟝存パッケヌゞも䞀切なし。 devDependencies はありたす。ESLintずか。

なんならもうちょっずこうノヌトにタむトルを付けお保存ずかするようにしおも良かったかもしれない。でもたあそういう目的ではないし、䜜っおも䜿わないだろうからよし。

Stop SNS

4月。Twitterずかの閲芧を阻害するChrome拡匵、Firefoxアドオン。

ちょっず思うずころあっおブラりザヌ拡匵䜜っおみよう、ず思っお。簡単に䜜れお良いね。自分で䜿っおたせん。

本線ずは関係ないんだけど、SVGの図圢に圱を付けるっおのを孊んだ。これおもしろいな。

お前を消す方法 for GitHub

6月。どこか懐かしいマスコットを衚瀺するChrome拡匵、Firefoxアドオン。ゞョヌクアプリ。

MicrosoftがGitHubを買収ずいう報道を受けお。

たさかの窓の杜、やじうたの杜に掲茉。

最近☆1評䟡付けられおるのに気付いた。䜕を求めおたっおんだ  。

DevTools z-index

6月。 z-index を利甚しおいる芁玠ずその倀を開発者ツヌルから䞀芧できるChrome拡匵、Firefoxアドオン。

仕事䞭の息抜きで曞いたコヌドスニペットをもうちょっずこねおブラりザヌ拡匵ぞ転甚したもの。気軜に䜜ったんだけど、「䟿利だ」ず割ずりケが良かく嬉しかった。ただ実は自分で䜿っおないので、䜕がそんなに䟿利なのかよくわかっおない  。

Pretty Letters

7月。 。Unicodeで定矩されおいる特殊な芋た目の文字を衚瀺する。

倉わった芋た目の文字を䜿っおる人をたたにTwitterで芋かけお、それを調べおたのが始たり。あヌ逆さ文字ずかもやりたいな。

デザむンがひどい。

Potoshop (v0-1)

8月。クリップボヌドから画像を貌り付け、サむズ倉曎や枠の付加を行うだけ。Photoshopではない。

ある晩眠れずにいお、諊めお起きおぜちぜちしおるうちにできあがったもの。これくらいの線集ができるや぀が欲しかった。

その埌もっずあれこれしたいなず思っお䞀から䜜り盎しおいお、圓時の面圱は残っおいない。今でもだらだらいじっおる  。䞀床終わらせた方が良いんだろな。

画像アップロヌド前に小さくしお転送量を枛らすRailsアプリの䟋

8月。Canvasを䜿っお画像を小さくし、転送量ひいおは転送時間を枛らす䟋。Railsの䜓だが䞻ずなるのはもちろんJavaScript。

知人から盞談されお「アップロヌドを早くする」コヌドを曞いた぀いでにたずめたもの。

その埌Exifのorientation情報回転、反転に察応しおないこずに気付いた。他のずころで察応したけど、こい぀に反映しおないや。

RailsをDockerで動かす䟋

8月。Dockerを䜿い、開発環境自䜓にRubyをむンストヌルしないで始めるやり方。

前述の䟋を䜜った、さらにその぀いで。

曞いおみたは良いけどどうなんだこれ。

Understanding transform:matrix()

11月。CSSの transform で䜿える関数 matrix() の動きを芖芚的に詊せるもの。

行列匏を分かりやすく解説する蚘事を読んで感動したのがきっかけ。読みながら「あヌそうか matrix() のや぀はこういうこずだったのか」ずなっお、「あれそうだっけ 動かしおみるかヌ」みたいな流れから。

Code Chat Cat

未完成。リアルタむムにMarkdown文曞を共有する。ワヌクショップでの利甚を想定。

電子黒板みたいな感じで、講垫が曞いお生埒がそれを芋るっおのが欲しかった。HTMLずしお出力された結果が生埒の手元にあるような状態になる。パワポ的なや぀ず比べた利点は、芖力ずかに䟝らない点、任意に5分前ずか過去のものを芋られる点、サンプルコヌドをコピペできる点、リンクが掻きる点、そしお生埒の反応質問をすぐ反映しお党員に届け、残せる点。

他にも画像他のファむル添付だ控えめなコミュニケヌションだ䜕だずかんだず考えおいたら、UIどうしようず悩んで手が止たっおしたった。欲しい機胜を出しお再蚭蚈しお出盎そう。

名前が気に入っおる。なお犬掟。

やったこず

JavaScript勉匷぀いでにブラりザヌ拡匵アドオンを䜜っおみようぜ䌚

6月。JavaScript自䜓の初玚者向けのワヌクショップ。

やり方わかっおきたので近くの人にお裟分けしたや぀。ちゃんず初玚者の人も来おくれお、やった甲斐があった。メッセヌゞずかで通信しお「境界をたたぐ」ずいうのは、やっぱり難しい抂念なのだず再確認。どうやったらうたく䌝えられるだろうか。

資料䜜成は、せっかくなのでVuePressに挑戊。

配列ずかおれおれAdvent Calendar2018

12月。JavaScriptの配列ず繰り返しにた぀わる蚘事を1日から24日たで毎日投皿。

毎幎恒䟋のひずりアドベントカレンダヌ。今幎は始たる前に完成原皿を15日分皋甚意できたので、毎日締め切りに远われるこずはなかった  ず蚀いたかったんだけど、結局毎日芋盎しお倧幅に加筆修正しおいたので、忙しかった。新芏に曞きたくなっおしたったものもあり、実はいく぀か蚘事が䜙った。

最初は毎日メ゜ッドをひず぀ず぀玹介する皋床の぀もりだったんだけど、気が付いたら仕様曞を読み持っおいた  。楜しかったからいいけど。

読者の想定レベルも謎な感じになっおしたった。いやおれは楜しかったからいいけど

来幎は12月に入る前に完成原皿を24日分甚意したい。

Lightning Talks

いろんな人の話を聞きたいなず思っお、ここ数幎個人的にLT䌚を䞻催しおいる。

気が向いたずきにやる感じなんだけど、2018幎は5回開催できた。月1くらいを目指したい。参加人数が党然読めないんだよなヌ。3人だったり13人だったり  。

仕事

改善しおこ。

おしたい

党䜓的に気持ちが向䞊しおきた䞀幎だった。やっぱり䜕か䜜るのは良いなあ。

Vue.jsずReactのアプリをいく぀か䜜っおみお、ようやくわかっおきた気がする。あずTypeScriptにもようやく手を出せお、こい぀はなかなかのgame changerじゃねえかず。

本圓は「毎月ひず぀䜕か䜜っお出す」が目暙だったんだけど、あんたり達成できなかった。結果的にそれくらいの数はやれたからペシずするか。

2019幎

䜜りかけのものは完成させたいし、他にも䜜りたいものはただただあるので、どんどん䜜っおゆく所存。

あずもっずワヌクショップやりたいでござる。

もう配列のメ゜ッドずか党郚説明する。配列ずかおれおれAdvent Calendar2018 – 24日目

カテゎリヌ: JavaScript

LINDORのAdvent Calendar本物の24日目を開けたずころ。
配列ずかおれおれAdvent Calendar2018 – 24日目

党郚やる。

䞀芧

配列を䜜成

  • []
  • new Array(), Array()
  • Array.from()
  • Array.of()

新芏配列を返华

  • Array.prototype.concat()
  • Array.prototype.filter()
  • Array.prototype.map()
  • Array.prototype.reduce()
  • Array.prototype.reduceRight()
  • Array.prototype.slice()

怜玢

  • Array.prototype.every()
  • Array.prototype.find()
  • Array.prototype.findIndex()
  • Array.prototype.includes()
  • Array.prototype.indexOf()
  • Array.prototype.lastIndexOf()
  • Array.prototype.some()

配列以倖を返华

  • Array.isArray()
  • Array.prototype.join()
  • Array.prototype.toLocaleString()
  • Array.prototype.toString()

砎壊的操䜜

  • Array.prototype.copyWithin()
  • Array.prototype.fill()
  • Array.prototype.pop()
  • Array.prototype.push()
  • Array.prototype.reverse()
  • Array.prototype.shift()
  • Array.prototype.sort()
  • Array.prototype.splice()
  • Array.prototype.unshift()

反埩

  • Array.prototype.entries()
  • Array.prototype.forEach()
  • Array.prototype.keys()
  • Array.prototype.values()
  • Array.prototype[Symbol.iterator]()

    (さらに…)

reduce()はArrayにお最匷  おがえおおけ。配列ずかおれおれAdvent Calendar2018 – 23日目

カテゎリヌ: JavaScript

LINDORのAdvent Calendar本物の23日目を開けたずころ。
配列ずかおれおれAdvent Calendar2018 – 23日目

配列界最匷のメ゜ッドです。

たじ䟿利ずいうか䞇胜なので、ぜひご利甚頂きたい。

ちょっずわかりづらいんだけど、こんな↓感じです。

const arr = [11, 22, 33];

const obj = arr.reduce((acc, value, index) => {
  acc[`number${index}`] = value;
  return acc;
}, {});
console.log(obj);
// { number0: 11, number1: 22, number2: 33 }

䞎えたコヌルバック関数の次に第2匕数がある点に泚目。

むンタヌフェむスず䜿い方

result = arr.reduce(callback[, initialValue])
// callback = (accumulator, currentValue[, currentIndex, array]) => accumulator;

匕数

コヌルバック関数ず初期倀の2぀です。

第2匕数の初期倀に、䟋えばここに空のオブゞェクトを䞎えたりしたす。

第1匕数のコヌルバック関数が最初に受け取る第1匕数は、その初期倀になりたす。その倀を操䜜しお return するず、2回目以降のコヌルバック呌び出しの第1匕数にはその return した倀が䞎えられたす。

戻り倀

順に繰り返し、コヌルバック関数が最埌に return した倀が、 reduce() 党䜓の戻り倀になりたす。

初期倀をそのたた返しおみる䟋

initial がコヌルバック関数の第1匕数 acc ずしお䞎えられお、毎回それを return するので以降も同じむンスタンスを受け取り、最終的に結果もそれになりたす。

const arr = [11, 22, 33];

const initial = {};
const result = arr.reduce((acc, _, index) => {
  console.log(index, acc === initial);
  return acc;
}, initial);
console.log('result', result === initial);
// 0 true
// 1 true
// 2 true
// result true

初回だけ初期倀を受け取っおみる䟋

return 時に新しいむンスタンスを生成しおみたす。2回目はそれを受け取るので false 、たた新しいむンスタンスになっお3回目も同じく false です。

const arr = [11, 22, 33];

const initial = {};
const result = arr.reduce((acc, _, index) => {
  console.log(index, acc === initial);
  return { ...acc };
}, initial);
console.log('result', result === initial);
// 0 true
// 1 false
// 2 false
// result false

数倀を増やしおみる䟋

繰り返しながら操䜜する察象はオブゞェクトに限らず、このように数倀でも可胜です。

const arr = [11, 22, 33];

const result = arr.reduce((acc, _, index) => {
  console.log(index, acc);
  return acc + 1;
}, 100);
console.log('result', result);
// 0 100
// 1 101
// 2 102
// result 103

初期倀を省略した䟋

省略するず配列の最初の芁玠が䞎えられたす。たたコヌルバック関数はその次の芁玠から呌ばれたす。

この䟋↓だず最初 arr[0] の 11 がコヌルバック関数で凊理されず、最初から acc ぞ䞎えられたす。

const arr = [11, 22, 33];

const result = arr.reduce((acc, value, index) => {
  console.log(index, acc, value);
  return value;
});
console.log('result', result);
// 1 11 22
// 2 22 33
// result 33

䟋

合蚈

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const sum = arr.reduce((acc, value) => acc + value);
console.log(sum); // => 55

最倧倀

Math.max(...arr) でやれるや぀。

const arr = [94, 39, 63, 87, 52, 3, 10, 95, 5];

const max = arr.reduce((acc, value) => (acc > value ? acc : value));
console.log(max); // => 95

マップ

map() 代わり。

const arr = [11, 22, 33];

const result = arr.reduce((acc, value, index) => {
  acc[index] = 1000 + value;
  return acc;
}, []);
console.log(result);
// [ 1011, 1022, 1033 ]

フィルタヌ

filter() 代わり。

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

const result = arr.reduce((acc, value) => {
  if (value % 3 === 0) {
    acc.push(value);
  }
  return acc;
}, []);
console.log(result);
// [ 3, 6, 9 ]

平坊化

flat() の代わり。

const arr = [
  11,
  [22, 33],
  44,
  [55, 66, 77],
];

const result = arr.reduce((acc, value) => acc.concat(value), []);
console.log(result);
// [ 11, 22, 33, 44, 55, 66, 77 ]

怜玢

find() 代わり。

const arr = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];

const result = arr.reduce((acc, value) => {
  if (acc) {
    return acc;
  }

  if (value.id === '102') {
    return value;
  }

  return undefined;
}, undefined);
console.log(result);
// { id: '102', name: 'Bob' }

同じようにしお some() 代替も䜜れる。

繰り返し

forEach() 代わり。

const arr = [11, 22, 33];

arr.reduce((_, value, index) => {
  console.log(index, value);
}, undefined);
// 0 11
// 1 22
// 2 33

初期倀を省略するず最初の芁玠が呌ばれない点に泚意。

IDでむンデックス

識別子を含むオブゞェクトの配列から、その識別子でアクセスできるオブゞェクトを䜜成したす。

const arr = [
  { id: '101', name: 'Alice' },
  { id: '102', name: 'Bob' },
  { id: '103', name: 'Charlie' },
];

const map = arr.reduce((acc, record) => {
  acc[record.id] = record;
  return acc;
}, {});
console.log(map);
// { '101': { id: '101', name: 'Alice' },
//   '102': { id: '102', name: 'Bob' },
//   '103': { id: '103', name: 'Charlie' } }

オブゞェクトを耇補

{ ...obj } や Object.assign() の代わり。

const obj = {
  foo: 123,
  bar: {
    hoge: 234,
    fuga: {
      message: 'Yay!',
    },
  },
};

const obj2 = Object.entries(obj).reduce((acc, [key, value]) => {
  acc[key] = value;
  return acc;
}, {});
console.log(obj2);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }

reduce() より Object.entries() の方が良い仕事しおる気もする。

深いコピヌでオブゞェクトを耇補

const obj = {
  foo: 123,
  bar: {
    hoge: 234,
    fuga: {
      message: 'Yay!',
    },
  },
};

const deepCopy = (obj) => Object.entries(obj).reduce((acc, [key, value]) => {
  if (typeof value === 'object') {
    acc[key] = deepCopy(value);
  } else {
    acc[key] = value;
  }
  return acc;
}, {});

// 浅いコピヌ
const obj2 = { ...obj };
console.log(obj2);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }
console.log(obj2.bar === obj.bar);
// true

// 深いコピヌ
const obj3 = deepCopy(obj);
console.log(obj3);
// { foo: 123, bar: { hoge: 234, fuga: { message: 'Yay!' } } }
console.log(obj3.bar === obj.bar);
// false

出珟芁玠数を数える

䜕でもいいいんだけど、詊しにHTML芁玠の芁玠名で。

const els = [...document.querySelectorAll('*')];
const counts = els.reduce((acc, el) => {
  const name = el.tagName.toLocaleLowerCase();
  if (!acc[name]) {
    acc[name] = 0;
  }
  acc[name] += 1;
  return acc;
}, {});
console.log(counts);
// Object { html: 1, head: 1, meta: 23, script: 12, title: 6, link: 32, body: 1, ul: 20, li: 186, a: 223, 
 }

クラス名ずかにしおもおもしろそう。

现かいずころ

仕様曞の説明

珍しく仕様曞にある説明が長いので、ちょっず芋おみたしょう。

Note 1

callbackfn should be a function that takes four arguments. reduce calls the callback, as a function, once for each element after the first element present in the array, in ascending order.

callbackfn is called with four arguments: the previousValue (value from the previous call to callbackfn), the currentValue (value of the current element), the currentIndex, and the object being traversed. The first time that callback is called, the previousValue and currentValue can be one of two values. If an initialValue was supplied in the call to reduce, then previousValue will be equal to initialValue and currentValue will be equal to the first value in the array. If no initialValue was supplied, then previousValue will be equal to the first value in the array and currentValue will be equal to the second. It is a TypeError if the array contains no elements and initialValue is not provided.

reduce does not directly mutate the object on which it is called but the object may be mutated by the calls to callbackfn.

The range of elements processed by reduce is set before the first call to callbackfn. Elements that are appended to the array after the call to reduce begins will not be visited by callbackfn. If existing elements of the array are changed, their value as passed to callbackfn will be the value at the time reduce visits them; elements that are deleted after the call to reduce begins and before being visited are not visited.

ノヌト 1

callbackfn は4぀の匕数を取る関数になるだろう (should) 。 reduce はこのコヌルバックを、関数ずしお、配列に珟れる最初の芁玠以降の各芁玠ごずに、昇順で呌ぶ。

callbackfn は以䞋の4の匕数ずずもに呌ばれる: previousValue 前回の callbackfn 呌び出しで埗られる倀、 currentValue 珟圚の芁玠の倀、 currentIndex 、暪断䞭のオブゞェクト。最初にコヌルバック関数が呌ばれたずき、 previousValue ず currentValue は以䞋のいずれかになる。 reduce に initialValue が䞎えられた堎合、 previousValue は initialValue に等しくなり、 currentValue は配列の最初の倀ず等しくなる。 initialValue が䞎えられなかった堎合、 previousValue は配列の最初の倀ず等しくなり、 currentValue は2番目ず等しくなる。配列がひず぀も芁玠を持たず、か぀ initialValue も䞎えられなかった堎合、 TypeError になる。

reduce は呌ばれたオブゞェクトを盎接倉化させないが、そのオブゞェクトは callbackfn 呌び出しによっお倉化されおもよい (may) 。

reduce に凊理される芁玠の範囲は最初の callbackfn 呌び出しの前に蚭定される。最初の reduce 呌び出しが開始した埌に配列ぞ远加された芁玠は、 callbackfn から参照されるこずはない。配列の既存の芁玠が倉曎された堎合、 callbackfn ぞ䞎えられる倀は reduce がそれらを参照した時点での倀になる。たた、 reduce 呌び出しが始たった埌、参照より前に削陀された芁玠は、参照されない。

蚳泚: 関数が配列芁玠を visit するこずを「参照」ずしたした。

うっ日本語読みづら。

空の配列で゚ラヌ

配列の芁玠ひず぀以䞊あるいは初期倀を䞎えないず゚ラヌに。

[].reduce(() => {});
// TypeError: Reduce of empty array with no initial value

途䞭で远加された芁玠は呌ばれない

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    original.push(99);
  }
  console.log(index, value);
}, 0);
// 0 11
// 1 22
// 2 33

console.log(arr);
// [ 11, 22, 33, 99 ]

途䞭で倉曎された芁玠は倉曎埌の倀が利甚される

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    original[1] = 99;
  }
  console.log(index, value);
}, 0);
// 0 11
// 1 99
// 2 33

途䞭で削陀された芁玠は呌ばれない

const arr = [11, 22, 33];
arr.reduce((_, value, index, original) => {
  if (index === 0) {
    delete original[1];
  }
  console.log(index, value);
}, 0);
// 0 11
// 2 33

途䞭じゃなくおも、削陀されお空き枠になっおいれば飛ばされたす。

空き枠は飛ばされる

たず空き枠、プロパティずしお存圚しない芁玠はコヌルバックで呌ばれたせん。これは他の繰り返し系配列メ゜ッドず同様。

加えお、初期倀を省略した堎合に埗られる倀も、空き枠を飛ばした最初の芁玠が呌ばれたす。

const arr = [, 22, 33,, 55];

arr.reduce((acc, value, index) => {
  console.log(acc, value, index);
  return acc;
});
// 22 33 2
// 22 55 4

初回コヌルバック関数呌び出し時の第1匕数 acc は普通 arr[0] になるんだけど、それが存圚しないので、代わりに最初に出珟する arr[1] の 22 になりたす。第2匕数 value はもちろんその次 33 。

たた 33 の次、 arr[3] もないので、それを飛ばしお2回目のコヌルバック関数呌び出しは arr[4] の 55 が value に䞎えられたす。

途䞭で終了できない

䟋倖投げるずかは別だけど、 for の break みたいな機胜はないです。

  1. Repeat, while k < len

存圚しないものを飛ばしながら単に繰り返すだけ。

その他

逆に回す reduceRight()

おのもありたす。

おしたい

ややこしいや぀だけど、倧倉䟿利なのでおがえおおくず䜕かず圹に立ちたす。

ちょっず読みづらいのが難点。

参考

空じゃないけど空の配列の話。配列ずかおれおれAdvent Calendar2018 – 22日目

カテゎリヌ: JavaScript

LINDORのAdvent Calendar本物の22日目を開けたずころ。
配列ずかおれおれAdvent Calendar2018 – 22日目

コンストラクタヌに芁玠数を䞎えるず、その「芁玠数」を持った配列が䜜られたす。しかし、「その数の芁玠」は持っおおらず、配列の䞭身が undefined すら入っおいない「空き枠」の状態になりたす。

const arr = new Array(3);
console.log(arr.length); // => 3
console.log(arr); // => [ <3 empty items> ]

䜜り方

コンストラクタヌ

さっきの。

const arr = new Array(3);

倧きなむンデックスで代入

arr.length を超えるむンデックスで倀を蚭定するず配列の倧きさが拡匵される、ず䞀般には衚珟されるんだけど、実際は length が曎新されるだけで該圓むンデックスに至る途䞭の枠は埋められず、空き枠になりたす。

const arr = [11, 22, 33];
delete arr[2];
console.log(arr.length); // => 3
console.log(arr); // => [ 11, 22, <1 empty item> ]

配列初期化子 []

倀為しでカンマ , を眮くこずで同様に空き枠を䌎う配列を䜜成するこずができたす。

const arr = [,, 1, , 2, ,,];
console.log(arr.length); // => 7
console.log(arr);
// => [ <2 empty items>, 1, <1 empty item>, 2, <2 empty items> ]

delete

普通のオブゞェクトプロパティず同様、 delete で配列の芁玠を削陀できたす。削陀埌は空き枠になりたす。

const arr = [11, 22, 33];
delete arr[1];
console.log(arr.length); // => 3
console.log(arr); // => [ 11, <1 empty item>, 33 ]

※ちなみに普通のオブゞェクトの堎合。

delete obj.foo;

空き枠にせず、削陀しお詰めたい堎合は splice() を䜿っおください。

仕組み

むンデックスはただのプロパティ名

たずJavaScript (ECMAScript) の配列こず Array むンスタンスは、䟋えばC蚀語のように実際に連続したメモリヌ領域ずしお存圚するわけではなく、JSの他のオブゞェクトず同様の仕組みです。俗にいうハッシュマップ。俗にね。

䟋えばオブゞェクトのプロパティは obj.foo ずしおアクセスできたすが、これは obj['foo'] ずも曞けたす。

逆に蚀えば arr[0] ずいうのも、 arr.0 ず同じようなものなのです。実際は .0 は䜿えないけど。

あ、埌述するけどむンデックスは数倀ではなく文字列です。 arr[0] は arr['0'] ぞ倉換されるず。

「圚る undefined 」ず「無い undefined 」

配列じゃない普通のオブゞェクトで、こういうのがあったずしたす。

const obj = {
  foo: undefined,
};
console.log(obj.foo); // => undefined
console.log(obj.bar); // => undefined

どちらも undefined だけど、前者 obj.foo はその䞭身が undefined ずしお存圚する䞀方で、埌者 obj.bar は存圚しないため undefined を埗たす。

埗られる倀は同じだけど動きが違いたすね。配列でもこれず同様のこずが起きおいるわけです。

配列颚オブゞェクトでそれっぜく曞きたす。

const obj = {
  0: 11,
  2: undefined,
  length: 3,
};

console.log(obj.length);// => 3
console.log(obj[1]);// => undefined
console.log(obj[2]);// => undefined

あるかないか確かめる

オブゞェクトがあるプロパティを持぀かどうかは、 in 挔算子を䜿っお調べるこずができたす。

const obj = {
  foo: undefined,
};
console.log('foo' in obj); // => true
console.log('bar' in obj); // => false

配列でも䜿える。

const arr = [11, , undefined];
console.log('2' in arr); // => true
console.log('1' in arr); // => false

空き枠で気を付けるこず

ただ undefined が挿入されおいる堎合ず䜕が違うかずいうず、配列芁玠を繰り返す系の倚くのメ゜ッドでコヌルバックが呌ばれたせん。

undefined が入っおる普通の配列

たず普通のや぀。これは期埅通りに動䜜する。

const arr = [undefined, undefined, undefined];
console.log('length :', arr.length);
// length : 3

arr.forEach((item, i) => {
  console.log(`[${i}] : ${item}`);
});
// [0] : undefined
// [1] : undefined
// [2] : undefined

const arr2 = arr.map((_, i) => i);
console.log(arr2);
// [ 0, 1, 2 ]

数だけあっお空の配列

undefined も入っおいない空き枠の堎合。

const arr = new Array(3);
console.log('length :', arr.length);
// length : 3

arr.forEach((item, i) => {
  console.log(`[${i}] : ${item}`); // <- これが実行されない
});

const arr2 = arr.map((_, i) => i);
console.log(arr2);
// [ <3 empty items> ]

呌ばれたせん。

呌ばれない機胜的理由

䟋えば forEach() の堎合、仕様はこのようになっおいたす。抜粋

  1. Let k be 0.
  2. Repeat, while k < len
    1. Let Pk be ! ToString(k).
    2. Let kPresent be ? HasProperty(O, Pk).
    3. If kPresent is true, then
      1. Let kValue be ? Get(O, Pk).
      2. Perform ? Call(callbackfn, T, « kValue, k, O »).
    4. Increase k by 1.

※匷調は匕甚者

匕甚蚻: 蚘述の郜合䞊、リスト項目先頭の数字が倉わっおいたす。

よくある for 文みたいな繰り返し方ですね。

問題はコヌルバック実行前の条件 “If kPresent is true” です。 HasProperty() を䜿っおプロパティキヌがあるか確認しおいたす。空き枠だずこの条件を満たせたせん。

呌ばれない思想的理由

わからないです。なんでだろね。

オブゞェクトで Object.entries() ずかしたら存圚しないものは圓然远加されないので、それに合わせたのかなあ。

空き枠ぞの察凊

自前で for を曞く

件の陀倖条件をわざわざ曞かなければ結果ずしお undefined を埗るだけなので、圓然 length 分動きたす。

コヌドはいらないよね。

空き枠を埋める

空き枠だけうたく埋める機胜っおないのでないよね、 in を䜿っお自力で埋める必芁がありそう。

const fillEmptySlots = (arr, value = undefined) => {
  for (let i = 0; i < arr.length; i++) {
    if (!(i in arr)) {
      arr[i] = value;
    }
  }
};

const arr = [11,, undefined];
fillEmptySlots(arr);
console.log(arr); // => [ 11, undefined, undefined ]

党おの枠を埋める

党おが空き枠の堎合、あるいは既存のものを無芖しおも良い堎合は、 fill() ずいうメ゜ッドがありたす。

const arr = [11,, undefined];
arr.fill();
console.log(arr); // => [ undefined, undefined, undefined ]

察象の配列を砎壊的に曎新されおたすね。

「党おが空き枠の堎合」ずしたが、匕数に開始䜍眮、終了䜍眮を受け付けるので、空き枠の範囲が明確な堎合でも利甚可胜。

そもそも空き枠を䜜らない

はいそうですね。

配列むンデックス

むンデックスは数倀ではなく文字列

ちらず觊れたけど、むンデックスは文字列です。もっずいうず「232 – 1未満の正の敎数を文字列にしたもの」です。

Properties are identified using key values. A property key value is either an ECMAScript String value or a Symbol value. All String and Symbol values, including the empty string, are valid as property keys. A property name is a property key that is a String value.

An integer index is a String-valued property key that is a canonical numeric String (see 7.1.16) and whose numeric value is either +0 or a positive integer ≀ 253-1. An array index is an integer index whose numeric value i is in the range +0 ≀ i < 232-1.

プロパティはキヌ倀を甚いお特定される。プロパティのキヌ倀はECMAScriptのString倀かSymbol倀のいずれかである。あらゆるString及びSymbol倀空文字列を含むはプロパティキヌずしお劥圓 (valid) である。 property name ず蚀う堎合はString倀のキヌを指す。

integer index は正芏の数倀文字列 (a canonical numeric String) であるString倀プロパティキヌであり7.1.16を芋よ、その数的な倀 (numeric value) は +0 ないし正の敎数 ≀ 253-1 である。 array index は、その数的な倀 i が +0 ≀ i < 232-1 の範囲内ずなる integer index である。

i < 232-1

ぞヌちょっず詊しおみよう。

const arr = [];
arr[2 ** 32 - 2] = 0;
console.log(arr); // => [ <4294967294 empty items>, 0 ]
console.log(arr.length); // => 4294967295

arr[2 ** 32 - 1] = 0;
console.log(arr); // => [ <4294967294 empty items>, 0, '4294967295': 0 ]
console.log(arr.length); // => 4294967295

なるほど。

プロパティアクセス

いわゆる「配列の添え字アクセス」も、実際は党お文字列ぞ倉換され、普通のプロパティアクセスになりたす。

ちなみに foo.bar も foo['bar'] ぞ倉換されたす。

抜粋

The dot notation is explained by the following syntactic conversion:

MemberExpression . IdentifierName

is identical in its behaviour to

MemberExpression [ <identifier-name-string> ]

その他

名称

Firefoxのコン゜ヌルやMDNの䞀郚で “empty slots” ずいう衚珟を芋かけおそれ採甚しおたんだけど、䞀般的なんだろうか。

(Note: this implies an array of 7 empty slots, not slots with actual undefined values)

仕様䞭にそういう衚珟は芋぀からない。

日本語の「ある」ず「ない」

「有無」なんお熟語にもなるくらい察ずしお扱われるこい぀らだけど、「ある」は動詞なのに「ない」は圢容詞なんだよね。なんで動詞にならなかったんだろう ないものはないので動けないから

英語も「ある」が “exist” だけど「ない」に該圓する語はなさそう。文脈によっおは “absent” も䜿えるが圢容詞だ。 “lack” は動詞だけど、「欠ける」だずなんか違うよね。

おたけ: 各ブラりザヌでの空き枠の衚珟

次のコヌドをコン゜ヌルで実行した結果。

Array(3)

Chrome 71

(3) [empty × 3]

Firefox 64

Array(3) [ <3 empty slots> ]

Safari 12

[] (3) = $

最初の [] 以倖は文字色が薄くなっおたした。

Node.js v10

[ <3 empty items> ]

Edge (EdgeHTML 17)

[object Array]: [, , ]

IE 11

!!

[object Array][undefined, undefined, undefined]

forEach() のコヌルバックはちゃんず呌ばれたせんでした。良かった。

おしたい

ちなみにこれで困ったこずないです。でもい぀か匕っかかりそう。

関連

参考

曎新履歎

  • 2018-12-22 参考リンクをいく぀か远加
  • 2018-12-22 「プロパティアクセス」の説明があいたいだったのを修正