※スマホ対応はしてません。

タグ: filter

その名の通りのfilter()で絞り込み。(配列とかおれおれAdvent Calendar2018 – 12日目)

カテゴリー: JavaScript

LINDORのAdvent Calendar(本物)の12日目を開けたところ。
配列とかおれおれAdvent Calendar2018 – 12日目

配列の中から条件に合致するものだけに絞るやつです。

const users = [
  { id: 101, name: 'Alice', active: true },
  { id: 102, name: 'Bob', active: false },
  { id: 103, name: 'Charlie', active: true },
];

const activeUsers = users.filter((v) => v.active);
console.log(activeUsers);

仕様

配列のこれ系のメソッドと同じです。

newArray = arr.filter(callback(element[, index[, array]])[, thisArg])

引数

filter() は引数に、関数オブジェクト callback(element[, index[, array]]) をひとつ受け取ります。

与える関数には、3つの引数が与えられます。 また前述のように boolean 値を返してください。

  • value … 配列の要素
  • index … インデックス
  • array … 操作中の配列本体

戻り値

関数 callback が true (ないし truthy なもの)を返した際の要素だけを格納した、新しい配列を返します。

該当がなかった場合でも要素数0の配列を返します。

例

undefined を除く

何かやった結果として undefined 混じりの情報を得るみたいな場面。

const result = [
  'foo',
  undefined,
  '',
  'hoge',
  undefined,
  'bar',
];

const validResult = result.filter((v) => v !== undefined);
console.log(validResult); // => [ 'foo', '', 'hoge', 'bar' ]

空文字列等の falsy なものもまとめて除いで良い場合は (v) => v で。短い。

アクティブユーザーだけ

フラグを含むオブジェクトの配列から対象のものだけを抜き出す場面。

const users = [
  { id: 101, name: 'Alice', active: true },
  { id: 102, name: 'Bob', active: false },
  { id: 103, name: 'Charlie', active: true },
];

const activeUsers = users.filter((v) => v.active);
console.log(activeUsers);
// => [ { id: 101, name: 'Alice', active: true },
//      { id: 103, name: 'Charlie', active: true } ]

チェックボックスで選択されたものだけ

document.querySelectorAll() は複数の要素を配列風オブジェクト NodeList で返します。 [...els] でそれを本物の配列へ変換し、 filter() で選択されたものだけにしてから map() で要素からその値を取り出しします。

(コードは抜粋)

<form id="the-form">
  <input type="checkbox" name="favorite" value="apple"> Apple
  <input type="checkbox" name="favorite" value="banana"> Banana
  <input type="checkbox" name="favorite" value="orange"> Orange
</form>
const elFavorites = document.querySelectorAll('#the-form [name="favorite"]');
const favorites = [...elFavorites]
  .filter((el) => el.checked)
  .map((el) => el.value);
console.log(favorites);

他の配列で指定されたID

前項のチェックボックスがIDだったとして、また別の配列からをその選択されたやつだけに絞る場合。

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

const activeUsers = users.filter((v) => selectedIds.includes(v.id));
console.log(activeUsers);
// => [ { id: '101', name: 'Alice' }, { id: '102', name: 'Bob' } ]

その他のメソッド

「絞り込む」以外の用途に合うメソッドがあるので、それぞれ使い分けましょう。

絞り込んだ結果を使って何かするなら map()

find() 後に map() を組み合わせると便利です。

前述したチェックボックスの例を参考に。

ひとつだけ選択する

対象のものが1つとわかっている場合は find() が便利です。

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

const id = '102';
const targetUser = users.find((v) => v.id === id);
console.log(targetUser);
// => { id: '102', name: 'Bob' }

あるかどうかだけわかれば良いなら some()

const existing = users.some((v) => v.id === targetId);
if (existing) {
  console.log('あったよ。');
}
else {
  console.log('なかったよ。');
}

全てが合致するか確認するなら every()

おまけ: あのアイコン

配列とは関係ないんだけど、UI上でフィルターの意味でしばしば使われるじょうご(ろうと、漏斗)、英語だと funnel だそうです。

Font Awesomeの “filter” 。

ガンダムのファンネルは、最初はその形状から名づけられたとか。その後ファンネルだけで例の小型遠隔兵器を指すようになり、フィン・ファンネルとかシールド・ファンネルとか出てくると。発展するにつれ語源から遠ざかるのは世の常ですね。

今日こんにちは! 然様さようなら!

おしまい

関連

参考

(ビルトインの)フィルターは衰退しました。(Vue.js始めるおれおれアドベントカレンダー2016 – 13日目)

カテゴリー: JavaScript

Vue.js始めるおれおれアドベントカレンダー2016 – 13日目

簡単なフィルタは自作しなくても最初から用意されてたりしないかな、と思ったんだけど、v1にはあったものの現在v2では削除されたとか。

テキストを展開するためのフィルタは、現状はまだ利用できますが、すべてのフィルタが削除されました。それらの代わりに、(例えば日付のフォーマットには date-fns 、通貨処理には accounting と言った形で) より専門的なライブラリの使用を推奨します。

いや「vue フィルタ」とかで検索したら公式ドキュメントが出てきたんだけど、よく見たら古い版のドキュメントでした。

それでも使おうとすると

開発用(vue.js)の場合は警告が出ます。本番用(vue.min.js)では何も出ません。

[Vue warn]: Failed to resolve filter: capitalize
(found in anonymous component - use the "name" option for better debugging messages.)

エラーにはならないけど、フィルターがないので元の内容がそのまま出てきます。

自分で作ろう

同じ名前でカスタムフィルタを作って登録すれば良いらしい。

先のガイドに、一通りのフィルタの代替コードが掲載されてます。

つくりかた

こんな感じで、 Vue.filter に名前と実装を教えてあげる感じらしい。

Vue.filter('uppercase', function (value) {
  return result.toUpperCase()
})

あとコンストラクタ?コンポーネント?何と呼ぶの? まあこんな感じで指定することもできた。

var app = new Vue({
  el: '#app',
  data: {
    message: 'Hello World!'
  },
  filters: {
    uppercase: function (value) {
      return value.toUpperCase()
    }
  }
})
<div id="app">
  <h1>{{message | uppercase}}</h1>
</div>

昔あったフィルタの一覧

あんまり歴史を知らないけれどもこれで大丈夫ですか?

文字列以外のフィルタ

今回は自分の目的ではないんだけれども、例えば繰り返し時の並び替えなんかのフィルタも、前はあったけどv2でなくなったそうです。

よくわからないこと

キャッシュ

とかどうなってるんだろ? やっぱり {{theValue | myFilter}} みたいな書き方したら、 theValue 変更まで結果を確保して再計算しないようになってるんだろうか。

調べてない。

おしまい

観たことなかったけど面白いじゃないか。四年前かあ。

CSSで白抜き文字を作る方法。text-shadowで囲んでみよう。(CSS おれおれ Advent Calendar 2012 – 03日目)

カテゴリー: CSS

CSS おれおれ Advent Calendar 2012 – 03日目

text-shadowでテキストに影を付ける事ができます。

text-shadow: <x> <y> <blur> <color>;

<x>, <y>は影の座標、<blur>はぼやけで、それぞれpxなんかで指定します。

また影をカンマ,で区切って複数指定する事ができるので、ぼかしなしの影で囲ってやると、白抜きにしたり縁取りしたり出来ます。

割とよく使えるんじゃないかなーって思います。

実例

(さらに…)