- 一般的なツール関数
new Map#
new Map MDN: https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Map
const map = new Map();
map.set("first",1); // 出力構造 Map(2) {'first' => 1}
map.has("first") // true has表にキーが存在するか確認し、存在すればtrue、無ければfalse
map.get("first") // 1 キーに対応する値を取得し、無ければundefinedを返す
/**
* for of メソッドでMapを反復処理
*/
const map = new Map();
map.set(1,"one");
map.set(2,"two");
for (let [key,value] of map){ // keyとvalueを同時に取得
console.log(key,value) // 1,one 2,two
}
for (let key of map.keys()){ // キーのみを取得
console.log(key) // 1 2
}
/**
* 2つの数の和を求めるアルゴリズム
* @param {number[]} nums
* @param {number} target
* @return {number[]}
*/
const twoSum = function(nums, target) {
const map = new Map();
for(let i = 0;i<nums.length;i++){
if(map.has(target - nums[i])){
return [map.get(target - nums[i]),i]
}else{
map.set(nums[i],i)
}
}
};
const nums = [2,4,5,7,10]
const target = 14
twoSum(nums,target) // [1,4] target値に等しい各数値のインデックスを出力
文字列数字反転#
/**
* @param {number} num
* @return {boolean}
*/
const isPalindrome = function(num) {
if (num === 0){
return true;
}
const str = num + '';
let result = '';
for (let i = 0;i<str.length;i++){
result += str[str.length-1-i];
}
if (str === result){
return true;
}else{
return false;
}
}
文字列変換 -(キャメルケースからスネークケース / スネークケースからキャメルケース)#
/**
* スネークケースからキャメルケース
* @return
*/
const toHump = (result) => {
return result.replace(/\_(\w)/g, function(_, res){
return res.toUpperCase();
});
}
/**
* キャメルケースからスネークケース
* @return
*/
const toUnderline = (result) => {
return result.replace(/([A-Z])/g,"_$1").toLowerCase();
}
localStorage 操作#
class Catch {
constructor(isLocal = true) {
this.storage = isLocal ? localStorage : sessionStorage;
}
setItem(key, value) {
if (typeof value === "object") value = JSON.stringify(value);
this.storage.setItem(key, value);
}
getItem(key) {
try {
return JSON.parse(this.storage.getItem(key));
} catch (err) {
this.storage.getItem(key);
}
}
removeItem(key) {
this.storage.removeItem(key);
}
clear() {
this.storage.clear();
}
key(index) {
return this.storage.key(index);
}
length() {
return this.storage.lenght;
}
}
const localCache = new Catch();
const sessionCache = new Catch(false);
export { localCache, sessionCache };
cookie 操作#
/**
* cookieを取得
* @return string
*/
const getCookie = (name) => {
const strcookie = document.cookie;//cookie文字列を取得
const arrcookie = strcookie.split("; ");//分割
for ( let i = 0; i < arrcookie.length; i++) {
const arr = arrcookie[i].split("=");
if (arr[0] == name){
return arr[1];
}
}
return "";
}
/**
* すべてのcookieを取得
* @return string
*/
const print = () => {
const strcookie = document.cookie;//cookie文字列を取得
const arrcookie = strcookie.split(";");//分割
for ( let i = 0; i < arrcookie.length; i++) {
const arr = arrcookie[i].split("=");
console.log(arr[0] +"=" + arr[1]);
}
}
const print = () => {
return eval('({' + document.cookie.replaceAll('=', ":'").replaceAll(';', "',") + "'})");
}
/**
* cookieの増減改
*/
const cookieManager = {
set(key, val) {
//cookie設定メソッド
const date = new Date(); //現在の時間を取得
const expiresDays = 1; // 1日
date.setTime(date.getTime() + expiresDays * 24 * 3600 * 1000); //cookieが認識する時間にフォーマット
document.cookie = key + '=' + val + ';expires=' + date.toGMTString(); //cookieを設定
console.log(key + '=' + val + ';expires=' + date.toGMTString(),'val....')
},
get(key) {
//cookie取得メソッド
/*cookieパラメータを取得*/
const cookies = document.cookie.replace(/[ ]/g, ''); //cookieを取得し、フォーマットして空白文字を取り除く
const arrCookie = cookies.split(';'); //cookieを"セミコロン"で分割し、arrCookie配列に保存
let tips; //tips変数を宣言
for (let i = 0; i < arrCookie.length; i++) {
//forループを使用してcookieのtips変数を探す
const arr = arrCookie[i].split('='); //単一のcookieを"等号"で分割し、arr配列に保存
if (key == arr[0]) {
//変数名を一致させる。arr[0]はcookie名を指し、その変数がtipsであれば、条件文の代入操作を実行
tips = arr[1]; //cookieの値をtips変数に代入
break; //forループを終了
}
}
return tips;
},
del(key) {
//cookie削除メソッド
const date = new Date(); //現在の時間を取得
date.setTime(date.getTime() - 10000); //dateを過去の時間に設定
document.cookie = key + '=v; expires =' + date.toGMTString(); //cookieを設定
},
};
スロットリングとデバウンス(テストケース)#
/**
* デバウンス
*/
const debounce = (fn, delay) => {
let timer;
return function () {
const arg = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(() => {
fn.apply(this, arg);
}, delay);
};
};
/**
* スロットリング
*/
const throttle = (fn, delay) => {
let timer;
return function () {
let _this = this;
let args = arguments;
if (timer) {
return;
}
timer = setTimeout(function () {
fn.apply(_this, args);
timer = null;
}, delay);
};
};
/**
* タイムスタンプスロットリング
*/
function timestamThrottle(fn, delay) {
let previous = 0;
// クロージャを使用して関数を返し、外部のprevious変数を使用
return function () {
let now = new Date();
if (now - previous > delay) {
fn.apply(this, arguments);
previous = now;
}
};
}
/**
* テストケース
* デバウンス関数の例
*/
const debounceFn = debounce((e) => {
console.log(e);
}, 500); // デバウンス関数
document.onmousemove = (e) => {
debounceFn(e); // デバウンス関数に引数を渡す
};
コピー / カットの監視#
/**
* コピーを監視
*/
(function () {
document.addEventListener('copy', (e) => {
const selection = document.getSelection();
e.clipboardData.setData('text/plain', selection.toString().toUpperCase());
e.preventDefault();
e.stopPropagation();
let copy = (e.clipboardData || window.clipboardData).getData('text/plain');
copy = copy.replace(/style/gi, 'data-style');
console.log(copy, 'copy');
});
})();
/**
* カットを監視
*/
(function () {
document.addEventListener('cut', (e) => {
const selection = document.getSelection();
e.clipboardData.setData('text/plain', selection.toString().toUpperCase());
document.getSelection().deleteFromDocument();
e.preventDefault();
e.stopPropagation();
let cut = (e.clipboardData || window.clipboardData).getData('text/plain');
cut = cut.replace(/style/gi, 'data-style');
console.log(cut, 'cut');
});
})();
再帰#
/**
* 現在のデータのすべての親構造データを返す(自分自身を含む)
* @param list = []
* @param id: number
*/
function getParentId(list, id) {
for (let i in list) {
if (list[i].value == id) {
return [list[i]];
}
if (list[i].children) {
let node = getParentId(list[i].children, id);
if (node !== undefined) {
return node.concat(list[i]);
}
}
}
}
/**
* 指定データを再帰的に検索
* @param list = []
* @param id: number
*/
function getCurrent(list, id) {
for (let o of list || []) {
if (o.value == id) return o
const o_ = getCurrent(o.children, id)
if (o_) return o_
}
}
// parentId と id が同じ場合、idの子データになる
//初期データ
var data = [
{ id: 2, parentId: 1 },
{ id: 1 },
{ id: 3, parentId: 2 },
{ id: 5, parentId: 4 },
{ id: 4 },
];
//処理後のデータ
/*[
{
id: 1,
child: [{
id: 2,
parentId: 1,
child: [{
id: 3,
parentId: 2
}]
}]
},
{id: 4, child: [{id: 5, parentId: 4}]},
]*/
function returnData(arr) {
//初期に上級データがないもの
let parents = arr.filter((item) => !item.parentId);
//初期に上級データがあるもの
let childs = arr.filter((item) => item.parentId);
//データを再帰的に処理
function newData(parents, childs) {
parents.forEach((item) => {
childs.forEach((child, childIndex) => {
if (item.id === child.parentId) {
let newChilds = JSON.parse(JSON.stringify(childs));
newChilds.splice(childIndex, 1); //既に存在するデータを削除
item.childs = item.childs ? item.childs.push(child) : [child];
newData([child], newChilds);
} else {
return false;
}
});
});
}
newData(parents, childs);
return parents;
}
let a = [];
console.log((a = returnData(data)));
// フィルタリング
// 例
const memberList = [
{
name: "開発部",
member: [
{
name: "フロントエンド",
member: [
{
name: "張三",
age: 18,
member: [],
},
],
},
{
name: "バックエンド",
member: [
{
name: "李四",
age: 24,
member: [],
},
],
},
],
},
{
name: "マーケティング部",
member: [
{
name: "主管",
member: [
{
name: "王五",
age: 30,
member: [],
},
],
},
{
name: "マネージャー",
member: [
{
name: "老六",
age: 28,
member: [],
},
],
},
],
},
];
// name 値をフィルタリングし、配列形式で返す
const getAllMember = (arr) => {
let member = [];
arr.forEach(item => {
if (item.member && item.member.length) {
member = [
...member,
...getAllMember(item.member)
]
} else {
member.push(item.name);
}
});
return member;
}
// age が20未満のデータをフィルタリング
const filterMember = (key, data) => {
const filterList = [];
data.forEach((ele) => {
const { member, ...other } = ele;
if (member && member.length) {
const currentEle = {
member: [],
...other,
};
const result = filterMember(key, member);
if (result.length) {
currentEle.member = result;
filterList.push(currentEle);
}
} else if (other.age > key) {
filterList.push(other);
}
});
return filterList;
};
ユーザーが devtools を開いたかどうかの行動を監視#
(function () {
var devtools = {
open: false,
orientation: null,
};
var threshold = 160;
var emitEvent = function (state, orientation) {
window.dispatchEvent(
new CustomEvent("devtoolschange", {
detail: {
open: state,
orientation: orientation,
},
})
);
};
clearTimer = setInterval(function () {
var widthThreshold = window.outerWidth - window.innerWidth > threshold;
var heightThreshold = window.outerHeight - window.innerHeight > threshold;
var orientation = widthThreshold ? "vertical" : "horizontal";
if (
!(heightThreshold && widthThreshold) &&
((window.Firebug &&
window.Firebug.chrome &&
window.Firebug.chrome.isInitialized) ||
widthThreshold ||
heightThreshold)
) {
if (!devtools.open || devtools.orientation !== orientation) {
emitEvent(true, orientation);
}
devtools.open = true;
devtools.orientation = orientation;
} else {
if (devtools.open) {
emitEvent(false, null);
}
devtools.open = false;
devtools.orientation = null;
}
}, 500);
if (typeof module !== "undefined" && module.exports) {
module.exports = devtools;
} else {
window.devtools = devtools;
}
})();
windown.addEventListener("devtoolschange", function (e) {
console.log(e.detail)
});
特定の要素のリアルタイム変化を監視#
/**
* 特定の要素のリアルタイム変化を監視
*/
export const ListeningTagAttribute = () => {
setTimeout(() => {
//監視する要素を選択
const targetNode = document.getElementById('detail-content');
// コールバック関数を渡してオブザーバーインスタンスを作成
const observer = new MutationObserver((mutationsList, observer) => {
// 各変化をループ処理
for (let mutation of mutationsList) {
console.log(mutation, mutationsList)
if (mutation.type === 'attributes') {
console.log('属性値が変更されました:', mutation.attributeName, mutation.target.getAttribute(mutation.attributeName));
}
}
});
// オブザーバーオプションを設定
const config = { attributes: true, childList: false, subtree: false };
//ターゲットノードとオブザーバーの設定オブジェクトを渡す
observer.observe(targetNode, config);
}, 3000)
}
URL の解析 / URL パラメータのフィールド置換処理#
/**
* @param {string} url アドレス
* @param {string} arg 置換するパラメータ名
* @param {any} arg_val 置換するパラメータ
* @returns 処理後のurlを返す
*/
function changeURLArg(url,arg,arg_val){
let pattern=arg+'=([^&]*)';
let replaceText=arg+'='+arg_val;
if(url.match(pattern)){
let tmp='/('+ arg+'=)([^&]*)/gi';
tmp=url.replace(eval(tmp),replaceText);
return tmp;
}else{
if(url.match('[\?]')){
return url+'&'+replaceText;
}else{
return url+'?'+replaceText;
}
}
return url+'\n'+arg+'\n'+arg_val;
}
// オブジェクトに解析
function queryURLparams(url) {
let obj = {}
if (url.indexOf('?') < 0) return obj
let arr = url.split('?')
url = arr[1]
let array = url.split('&')
for (let i = 0; i < array.length; i++) {
let arr2 = array[i]
let arr3 = arr2.split('=')
obj[arr3[0]] = arr3[1]
}
return obj
}
function queryURLparamsRegEs5(url) {
let obj = {}
let reg = /([^?=&]+)=([^?=&]+)/g
url.replace(reg, function() {
obj[arguments[1]] = arguments[2]
})
return obj
}
function queryURLparamsRegEs6(url) {
let obj = {}
let reg = /([^?=&]+)=([^?=&]+)/g
url.replace(reg, (...arg) => {
obj[arg[1]] = arg[2]
})
return obj
}
/**
* @param {string} param urlアドレスの後に追加するパラメータ
* @returns
*/
function addParameterToURL(param) {
let _url = location.href;
_url += (_url.split('?')[1] ? '&' : '?') + param;
return _url;
}
UUID#
function UUID() {
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4";
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);
s[8] = s[13] = s[18] = s[23] = "-";
var UUID = s.join("");
return UUID;
}
function UUID() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
function UUID() {
function S4() {
return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
}
return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4());
}
function uuid2(len, radix) {
var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
var uuid = [],i;
radix = radix || chars.length;
if (len) {
for (i = 0; i < len; i++) uuid[i] = chars[0 | Math.random() * radix];
} else {
var r;
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4';
for (i = 0; i < 36; i++) {
if (!uuid[i]) {
r = 0 | Math.random() * 16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r];
}
}
}
return uuid.join('');
}
ファジー検索#
const listdata = [
{
id: 1,
name: "こんにちは",
},
{
id: 2,
name: "こんにちはhaha",
},
{
id: 3,
name: "xiaoyangこんにちは",
},
];
function fuzzyQuery(list, keyWord, arrtibute = "name") {
const reg = new RegExp(keyWord);
const arr = [];
for (let i = 0; i < list.length; i++) {
if (reg.test(list[i][arrtibute])) {
arr.push(list[i]);
}
}
return arr;
};
console.log(fuzzyQuery(listdata, "こんにちは", "name")); // [{id: 1, name: 'こんにちは'}1: {id: 3, name: 'xiaoyangこんにちは'}]
配列のフラット化#
const arr = [
{
id: 1,
name: 'node-1',
},
{
id: 2,
name: 'node-2',
children: [
{
id: 3,
name: 'node-3',
},
{
id: 4,
name: 'node-4',
children: [
{
id: 5,
name: 'node-5',
},
],
},
],
},
];
/**
* フラット化
*/
const result = arr.reduce(function (prev, current) {
prev.push({
id: current.id,
name: current.name,
parent: current.parentId,
});
current.children &&
current.children.forEach((v) => {
v.parentId = current.id;
arguments.callee(prev, v);
});
return prev;
}, []);
const map = [
{
id: 1,
name: 'ndoe-1',
parentId: undefined,
},
{
id: 2,
name: 'ndoe-2',
parentId: undefined,
},
{
id: 3,
name: 'ndoe-3',
parentId: 2,
},
{
id: 4,
name: 'ndoe-4',
parentId: 2,
},
{
id: 5,
name: 'ndoe-5',
parentId: 4,
},
];
/**
* フラット化からツリー構造に変換
*/
const result = map.reduce(function (prev, current, i, arr) {
current.children = a = arr.filter((v) => v.parentId === current.id);
if (!current.parentId) {
prev.push(current);
}
return prev;
}, []);
function flatten(arr) {
let result = [];
for (let i = 0; i < arr.length; i++) {
if (Array.isArray(arr[i])) {
result = result.concat(flatten(arr[i]));
} else {
result.push(arr[i]);
}
}
return result;
};
function flatMap(list = [], id: number) {
return list.flatMap(({children, ...other}) => {
return [other].concat(flatMap(children))
})
}
重複排除#
// 配列オブジェクトの重複排除
const duplicateRemoval = edgesdata.filter((item) => !line.some((ele) => ele?.id === item?.id));
// 配列の重複排除 [1,2,1,2,1,3,3,3]
function duplicateRemoval(arr) {
const res = new Map();
return arr.filter((arr) => !res.has(arr.id) && res.set(arr.id, 1));
}
// 配列の重複排除 [1,2,1,2,1,3,3,3]
const duplicateRemoval = (arr) => [...new Set(arr)];
// 配列の重複排除と同じデータのマージ
function handlerArrayMerge(value){
const tempIds = [],newArrs = [];
for(const item of value){
if(!tempIds.includes(item.id)){
tempIds.push(item.id);
newArrs.push(item);
}else{
for(const ele of newArrs){
if(ele.id === item.id){
ele.children = handlerArrayMerge(ele.children.concat(item.children));
}
}
}
}
return newArrs;
}
正規表現による検証#
// 文字列がhtml形式かどうかを判断
function isHtml(str) {
return /<[a-z]+\d?(\s+[\w-]+=("[^"]*"|'[^']*'))*\s*\/?>|&#?\w+;/i.test(str);
}
数字の処理#
const num = 12.34567;
// 小数点以下2桁を保持し、四捨五入しない
Math.floor(num * 100) / 100 // 出力結果は 12.34
// 小数点以下2桁を保持し、四捨五入
num.toFixed(2); // 出力結果は 12.35
//四捨五入して小数点以下2桁を保持(足りない桁は0で補う)
function keepTwoDecimals(num) {
let result = parseFloat(num);
if (isNaN(result)) {
// パラメータが要件を満たさない
return false;
}
result = Math.round(num * 100) / 100;
let rt = result.toString();
let pos = rt.indexOf('.');
if (pos < 0) {
pos = rt.length;
rt += '.';
}
while (rt.length <= pos + 2) {
rt += '0';
}
return rt;
}
keepTwoDecimals(124); // 出力結果 124.00
タイマー処理#
/**
* タイマーの計時、停止、再開
*/
class timerRecording {
timerId = undefined;
// 一時停止時の時間を記録するための変数を定義
pauseTime = 0;
// タイマー開始時間を記録するための変数を定義
startTime = 0;
startTimer() {
// すでにタイマーが実行中の場合は、直接戻る
if (this.timerId) {
return;
}
// タイマー開始時間を記録
this.startTime = Date.now();
// タイマーを起動し、1秒ごとにコールバック関数を実行
this.timerId = setInterval(() => {
// 経過時間を計算
let elapsed = Date.now() - this.startTime + this.pauseTime;
// 経過時間をHH:MM:SS形式にフォーマット
// let hours = Math.floor(elapsed / (60 * 60 * 1000));
// let minutes = Math.floor((elapsed - hours * 60 * 60 * 1000) / (60 * 1000));
// let seconds = Math.floor((elapsed - hours * 60 * 60 * 1000 - minutes * 60 * 1000) / 1000);
// let timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
// 累積秒数に変換
let seconds = parseInt(elapsed / 1000);
// フォーマットされた時間を現在の記事のタグ属性に表示
document
.getElementById('detail-content')
?.setAttribute('data-time', seconds);
}, 1000);
}
// タイマーを一時停止
pauseTimer() {
// タイマーが実行中でない場合は、直接戻る
if (!this.timerId) {
return;
}
// タイマーをクリア
clearInterval(this.timerId);
// 一時停止時の時間を記録
this.pauseTime += Date.now() - this.startTime;
// タイマーIDをクリア
this.timerId = null;
}
// タイマーを再開
continueTimer() {
// すでにタイマーが実行中の場合は、直接戻る
if (this.timerId) {
return;
}
// タイマー開始時間を記録
this.startTime = Date.now();
// タイマーを起動し、1秒ごとにコールバック関数を実行
this.timerId = setInterval(() => {
// 経過時間を計算
let elapsed = Date.now() - this.startTime + this.pauseTime;
// 経過時間をHH:MM:SS形式にフォーマット
// let hours = Math.floor(elapsed / (60 * 60 * 1000));
// let minutes = Math.floor((elapsed - hours * 60 * 60 * 1000) / (60 * 1000));
// let seconds = Math.floor((elapsed - hours * 60 * 60 * 1000 - minutes * 60 * 1000) / 1000);
// let timeString = `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${seconds.toString().padStart(2, '0')}`;
// 累積秒数に変換
let seconds = parseInt(elapsed / 1000);
// フォーマットされた時間を現在の記事のタグ属性に表示
document
.getElementById('detail-content')
?.setAttribute('data-time', seconds);
}, 1000);
}
}
const timerRecord = new timerRecording();
export { timerRecord };