JavaScript#
JS 文法集#
call 関数の実装#
Function.prototype.wxcall = function (thisArg, ...arg) {
var fn = this;
thisArg = thisArg ? Object(thisArg) : window;
thisArg.fn = fn;
return thisArg.fn(...arg);
};
console.log(foo.wxcall('abc', 10, 20));
console.log(foo.wxcall({}, 10, 20));
let result = foo.wxcall(null, 10, 20);
console.log(result);
apply 関数の実装#
Function.prototype.wxapply = function (thisArg, arrArg) {
var fn = this;
thisArg = thisArg ? Object(thisArg) : window;
thisArg.fn = fn;
arrArg ? thisArg.fn(...arrArg) : thisArg.fn(); //引数が渡されたか
delete thisArg.fn;
};
function foo(a, b, c) {
console.log(a + b + c);
}
foo.wxapply({}, [10, 20, 30]);
foo.wxapply({}, [10, 20, 30]);
slice 関数の実装#
Array.prototype.wxslice = function (start, end) {
var arr = this;
let newArr = [];
for (let i = start; i < end; i++) {
newArr.push(arr[i]);
}
return newArr;
};
console.log([1, 2, 3, 4, 5, 6, 7, 8].wxslice(0, 2));
defineProperty#
const obj = {
name: 'Tom',
age: 18,
};
// Object.defineProperty(obj,'name',{
// get:function(){
// console.log('nameプロパティがアクセスされました');
// },
// set:function(){
// console.log('nameプロパティが設定されました');
// }
// })
// console.log(obj.name); //nameプロパティがアクセスされました
// obj.name = 'Kobe' //nameプロパティが設定されました
// オブジェクトのすべてのキーを取得できます
Object.keys(obj).forEach(key => {
let value = obj[key];
console.log(key);
/* name
age
*/
Object.defineProperty(obj, key, {
get: function () {
console.log('プロパティがアクセスされました');
return value;
},
set: function (newValue) {
console.log('nameプロパティが設定されました');
},
});
});
console.log(obj.name); //nameプロパティがアクセスされました
obj.name = 'Kobe'; //nameプロパティが設定されました
Proxy 代理#
const obj = {
name: 'Tom',
age: 18,
height: 1.88,
};
// プロキシ代理を作成
// パラメータ1:objオブジェクトを代理 パラメータ2:トラップ(13種類のトラップがあります)
const objProxy = new Proxy(obj, {
// 値を取得するトラップ(値を取得するときに自動的にこの関数がコールバックされます)
get: function (target, key) {
// targetは代理されたオブジェクト; key
console.log(target); //{ name: 'Tom', age: 18, height: 1.88 }
console.log(key); // nameが取得されたときのkey
return target[key];
},
// 値を設定するトラップ(値を設定するときに自動的にこの関数がコールバックされます)
set: function (target, key, newValue) {
target[key] = newValue;
},
});
// アクセス
// console.log(objProxy); // { name: 'Tom', age: 18, height: 1.88 }
// console.log(objProxy.name); // Tom
// console.log(objProxy.age); // 18
// 設定
// objProxy.name = "Kobe"; // プロキシを通して
console.log(objProxy.name); // Kobe
反応性の原理#
class Depend {
constructor() {
this.reactiveFns = [];
}
// 依存関係を収集
addDepend(reactiveFn) {
this.reactiveFns.push(reactiveFn);
}
// 依存関係を実行
notify() {
// すべての依存関係をループして実行
this.reactiveFns.forEach(fn => {
fn();
});
}
}
const depend = new Depend();
const obj = {
name: 'Tom',
age: 18,
};
// プロキシやObject.definePropertyを使ってプロパティの変化を監視し、depend.notify()を実行
const objProxy = new Proxy(obj, {
get: function (target, key, receiver) {
// 値を取得して返す
return Reflect.get(target, key, receiver);
},
// プロキシオブジェクトに値を設定するときに自動的にこのメソッドが実行されます
set: function (target, key, newvalue, receiver) {
Reflect.set(target, key, newvalue, receiver);
// 値を設定するときにdependに通知して依存関係を実行
depend.notify();
},
});
function foo() {
console.log('コードを実行');
}
depend.addDepend(foo); //依存関係を収集
objProxy.name = 'Lilei';
イテレータ#
// イテレータは以下の条件を満たす必要があります
// 一、オブジェクトであること
// 二、オブジェクトにnextメソッドがあること
// 三、そのメソッドがオブジェクトを返し、そのオブジェクトにはdoneとvalueプロパティがあること
// const iterator = {
// next: function () {
// return { done: true, value: "" };
// },
// };
// 配列
const arr = ['abc', 'cba', 'nba'];
// イテレータを使って配列を走査
// 配列にアクセスするためのイテレータオブジェクトを作成
let index = 0;
const arrIterator = {
next: function () {
if (index < arr.length) {
return { done: false, value: arr[index++] };
} else {
return { done: true, value: undefined };
}
},
};
console.log(index); //0
console.log(arrIterator.next()); //{ done: false, value: 'abc' }
console.log(index); //1
console.log(arrIterator.next()); //{ done: false, value: 'cba' }
console.log(index); //2
console.log(arrIterator.next()); //{ done: false, value: 'nba' }
console.log(index); //3
console.log(arrIterator.next()); //{ done: true, value: undefined }
console.log(index); //3
// イテレータの最適化
イテレータ生成関数#
function createArryIterator(arr) {
let index = 0;
return {
next: function () {
if (index < arr.length) {
return { done: false, value: arr[index++] };
} else {
return { done: true, value: undefined };
}
},
};
}
const names = ['Tom', 'Sily', 'Lusy'];
const nameIterator = createArryIterator(names);
console.log(nameIterator.next()); //{ done: false, value: 'Tom' }
console.log(nameIterator.next()); //{ done: false, value: 'Sily' }
console.log(nameIterator.next()); //{ done: false, value: 'Lusy' }
const nums = [1, 2, 3, 4, 5];
const numsIterator = createArryIterator(nums);
console.log(numsIterator.next()); //{ done: false, value: 1 }
console.log(numsIterator.next()); //{ done: false, value: 2 }
console.log(numsIterator.next()); //{ done: false, value: 3 }
console.log(numsIterator.next()); //{ done: false, value: 4 }
// 無限イテレータを作成
function createNumberIterator() {
let index = 0;
return {
next: function () {
return {
done: false,
value: index++,
};
},
};
}
const numberInterator = createNumberIterator();
console.log(numberInterator.next()); //{ done: false, value: 0 }
console.log(numberInterator.next()); //{ done: false, value: 1 }
console.log(numberInterator.next()); //{ done: false, value: 2 }
console.log(numberInterator.next()); //{ done: false, value: 3 }
console.log(numberInterator.next()); //{ done: false, value: 4 }
console.log(numberInterator.next()); //{ done: false, value: 5 } ......
イテレータオブジェクト#
// このオブジェクトはイテレータを返します
const iterabalObj = {
names: ['Tom', 'Sily', 'Lusy'],
// イテラブルオブジェクトは[Symbol.iterator]というプロパティを持ち、その関数がイテレータを返す必要があります
[Symbol.iterator]: function () {
let index = 0;
return {
next: () => {
if (index < this.names.length) {
return { done: false, value: this.names[index++] };
} else {
return { done: true, value: undefined };
}
},
};
},
};
console.log(iterabalObj[Symbol.iterator]); //[Function: [Symbol.iterator]]
// この関数を呼び出すと新しいイテレータが生成されます
const iterator = iterabalObj[Symbol.iterator]();
console.log(iterator.next()); //{ done: false, value: 'Tom' }
console.log(iterator.next()); //{ done: false, value: 'Sily' }
console.log(iterator.next()); //{ done: false, value: 'Lusy' }
// 新しいイテレータ
const iterator1 = iterabalObj[Symbol.iterator]();
console.log(iterator1.next()); //{ done: false, value: 'Tom' }
console.log(iterator1.next()); //{ done: false, value: 'Sily' }
console.log(iterator1.next()); //{ done: false, value: 'Lusy' }
for (const item of iterabalObj) {
console.log(item);
// Tom
// Sily
// Lusy
}
ジェネレーター#
// ジェネレーター関数(*)
function* foo() {
console.log(1);
yield;
console.log(2);
// yieldは関数を停止させることができます
yield;
console.log(3);
yield;
console.log(4);
}
// ジェネレーター関数を呼び出すと、その関数は直接実行されず、ジェネレーターオブジェクトが返されます
// console.log(foo()); // Object [Generator] {}
const Generator = foo();
// 最初のコードブロック(yieldの前のコード)を実行し、next()を実行します
Generator.next(); //1
// 次のコードブロックを実行
Generator.next(); //2
// 次のコードブロックを実行
Generator.next(); //3
// 次のコードブロックを実行
Generator.next(); //4
ジェネレーター関数の実行フロー#
function* foo() {
console.log(1);
yield '返り値'; //このコードブロックの返り値
console.log(2);
yield;
console.log(3);
yield;
console.log(4);
}
const Generator = foo();
// 返り値はvalue ,done:false
console.log(Generator.next()); // { value: { name: 'tom', age: 18 }, done: false }
// Generator.next() // 1
// ジェネレーター関数 function*
// yieldキーワードはコードをここで一時停止させることができます
// ジェネレーター関数を実行すると、ジェネレーターオブジェクトが返されます
// このジェネレーターオブジェクトのnextメソッドを呼び出すと、yieldの前のコードが順に実行されます
// 再度next()を呼び出すと、次のyieldの前のコードが続けて実行されます
// 各yieldの前のコードが何らかの値を返したい場合は、その返り値をyieldの後に書くことができます
ジェネレーターの引数問題#
// 各コードブロックの引数問題
function* foo() {
console.log(1);
// 2回目のnext関数の実行時に渡された引数は、最初のyieldの返り値に代入されます
const n = yield;
// 2番目のコードブロックは2回目のnextの実行時に実行されます
console.log(2 * n); // 20
yield '返り値 :console.log(Generator.next()) // 返り値 ......';
console.log(3);
yield;
console.log(4);
}
const Generator = foo();
Generator.next();
Generator.next(10);
// Generator.next()を2回実行します
// 2回目の実行時に引数が渡されます
// この引数は最初のyieldの返り値として使用され、const n = yieldでnを使用してその返り値を受け取ります
マクロタスクとマイクロタスク#
// awaitの後のコードはマイクロタスクに属します
// async function a() {
// console.log('a')
// await b()
// console.log('a end')
// }
// async function b() {
// console.log('b')
// }
// a()
// setTimeout(function () {
// console.log('setTimeout')
// }, 0)
// new Promise(function (resolve, reject) {
// console.log('promise')
// resolve()
// }).then(function () {
// console.log('then')
// })
// console.log('main end')
// //
setTimeout(function () {
console.log('8');
}, 0);
async function async1() {
console.log('1');
const data = await async2();
console.log('6');
return data;
}
async function async2() {
return new Promise(resolve => {
console.log('2');
resolve('async2の結果');
}).then(data => {
console.log('4');
return data;
});
}
async1().then(data => {
console.log('7');
console.log(data);
});
new Promise(function (resolve) {
console.log('3');
resolve();
}).then(function () {
console.log('5');
});
//
console.log('script start');
async function async1() {
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2 end');
}
async1();
setTimeout(function () {
console.log('setTimeout');
}, 0);
new Promise(resolve => {
console.log('Promise');
resolve();
})
.then(function () {
console.log('promise1');
})
.then(function () {
console.log('promise2');
});
console.log('script end');
//
// console.log('script start')
// async function async1() {
// await async2()
// console.log('async1 end')
// }
// async function async2() {
// console.log('async2 end')
// return Promise.resolve().then(()=>{
// console.log('async2 end1')
// })
// }
// async1()
// setTimeout(function() {
// console.log('setTimeout')
// }, 0)
// new Promise(resolve => {
// console.log('Promise')
// resolve()
// })
// .then(function() {
// console.log('promise1')
// })
// .then(function() {
// console.log('promise2')
// })
// console.log('script end')
// async function async1(){
// await async2()
// console.log('async1 end')
// }
// async function async2(){}
// async1();
// new Promise(function(resolve){
// resolve();
// }).then(function(){
// console.log('promise2')
// }).then(function() {
// console.log('promise3')
// }).then(function() {
// console.log('promise4')
// })
デバウンス#
function debounce(fn, delay) {
let timer = null;
return (...args) => {
if (timer) clearTimeout(timer);
timer = setTimeout(() => {
fn.apply(this, args);
}, delay);
};
}
// 最初に直接実行するかどうか
function debounce(fn, delay, isImmediately = true) {
let timer = null;
let Immediately = isImmediately;
return (...args) => {
if (timer) clearTimeout(timer);
Immediately
? fn.apply(this, args)
: (timer = setTimeout(() => fn.apply(this, args), delay));
Immediately = !isImmediately;
};
}
スロットリング#
function throttle(fn, delay) {
let pre = 0;
return (...args) => {
let now = new Date();
if (now - pre > delay) {
fn.apply(this, args);
}
pre = now;
};
}
深いコピー#
function isObject(value) {
const valueType = typeof value;
return (value !== null && valueType === 'object') || valueType === 'function';
}
function deepClone(originValue) {
// symbol型かどうかを判断し、新しいsymbolを作成
if (typeof originValue === 'symbol') {
return Symbol(originValue.description);
}
if (typeof originValue === 'function') {
// 関数であればそのまま返す
return originValue;
}
if (originValue instanceof Set) {
return new Set([...originValue]);
}
if (originValue instanceof Map) {
return new Map([...originValue]);
}
// 渡されたoriginがオブジェクト型かどうかを判断
if (!isObject(originValue)) {
return originValue;
}
// 渡されたオブジェクトが配列かオブジェクトかを判断
const newObject = Array.isArray(originValue) ? [] : {};
// 元のオブジェクトをループし、元のオブジェクトのプロパティ値を新しいオブジェクトにコピー
for (const key in originValue) {
newObject[key] = deepClone(originValue[key]); // 再帰呼び出し
}
const symbolKeys = Object.getOwnPropertySymbols(originValue);
for (const skey of symbolKeys) {
newObject[skey] = deepClone(originValue[skey]);
}
return newObject;
}
const obj1 = {
name: 'Tom',
fridends: {
one: {
name: 'sily',
},
tow: {
name: 'kobe',
},
},
};
console.log(deepClone(obj1));
イベントバス#
class EventBus {
constructor() {
this.eventBus = {};
}
on(eventName, eventCallBack, thisArg) {
let handlers = this.eventBus[eventName];
if (!handlers) {
handlers = [];
this.eventBus[eventName] = handlers;
}
handlers.push({
eventCallBack,
thisArg,
});
}
off() {}
emit(eventName, ...payload) {
const handlers = this.eventBus[eventName];
if (!handlers) return;
handlers.forEach(handler => {
handler.eventCallBack.apply(handler.thisArg, payload);
});
}
}
const eventBus = new EventBus();
// mian.js
eventBus.on(
'a',
function (payload) {
console.log(payload);
},
this
);
// utill.js
eventBus.emit('a', { name: 'Tom' });
slice 関数の実装#
Array.prototype.wxslice = function (start, end) {
var arr = this
let newArr = []
for (let i = start; i < end; i++) {
newArr.push(arr[i])
}
return newArr
}
console.log([1, 2, 3, 4, 5, 6, 7, 8].wxslice(0, 2));
call 関数の実装#
// すべての関数にwxapplyメソッドを追加
// Function.prototype.wxcall = function (thisArg, ...arg) { //thisと引数を渡す
// // ここでこのメソッドを呼び出した関数を実行できるようにする
// // 問題:どの関数がcallを実行したのか
// var fn = this //誰が呼び出したかがthis
// // thisArgをオブジェクト型に変換し、数値や他の非オブジェクト型が渡されるのを防ぐ
// // もし渡されたのがNullまたはundefinedであれば、thisをwindowにバインドする
// thisArg = thisArg ? Object(thisArg) : window
// thisArg.fn = fn //その関数を実行
// thisArg.fn(...arg) //thisと引数をバインド
// delete thisArg.fn
// }
// function foo(a, b) {
// console.log('実行');
// console.log(this);
// console.log(a + b);
// }
// foo.wxcall({}, 10, 20)
// Function.prototype.wxcall = function (thisArg, ...arg) {
// var fn = this
// thisArg = thisArg ? Object(thisArg) : window
// thisArg.fn = fn
// thisArg.fn(...arg)
// }
// function foo(a, b) {
// console.log(a + b);
// }
// foo.wxcall({}, 10, 20)
// foo.wxcall(123, 10, 20)
Function.prototype.wxcall = function (thisArg, ...arg) {
var fn = this
thisArg = thisArg ? Object(thisArg) : window
thisArg.fn = fn
return thisArg.fn(...arg)
}
function foo(a, b) {
return a + b
}
console.log(foo.wxcall('abc', 10, 20));
console.log(foo.wxcall({}, 10, 20));
let result = foo.wxcall(null, 10, 20)
console.log(result);
イテレータを生成する関数#
function createArryIterator(arr){
let index = 0
return {
next:function(){
if(index < arr.length){
return { done:false, value:arr[index++]}
}else{
return { done:true, value:undefined}
}
}
}
}
const names = ['Tom','Sily','Lusy']
const nameIterator = createArryIterator(names)
console.log(nameIterator.next()); //{ done: false, value: 'Tom' }
console.log(nameIterator.next()); //{ done: false, value: 'Sily' }
console.log(nameIterator.next()); //{ done: false, value: 'Lusy' }
const nums = [1,2,3,4,5]
const numsIterator = createArryIterator(nums)
console.log(numsIterator.next()); //{ done: false, value: 1 }
console.log(numsIterator.next()); //{ done: false, value: 2 }
console.log(numsIterator.next()); //{ done: false, value: 3 }
console.log(numsIterator.next()); //{ done: false, value: 4 }
// 無限イテレータを作成
function createNumberIterator(){
let index = 0
return {
next:function(){
return {
done:false,
value:index++
}
}
}
}
const numberInterator = createNumberIterator()
console.log(numberInterator.next()); //{ done: false, value: 0 }
console.log(numberInterator.next()); //{ done: false, value: 1 }
console.log(numberInterator.next()); //{ done: false, value: 2 }
console.log(numberInterator.next()); //{ done: false, value: 3 }
console.log(numberInterator.next()); //{ done: false, value: 4 }
console.log(numberInterator.next()); //{ done: false, value: 5 } ......
apply 関数の実装#
Function.prototype.wxapply = function (thisArg, arrArg) {
var fn = this
thisArg = thisArg ? Object(thisArg) : window
thisArg.fn = fn
arrArg ? thisArg.fn(...arrArg) : thisArg.fn() //引数が渡されたか
delete thisArg.fn
}
function foo(a, b, c) {
console.log(a + b + c);
}
foo.wxapply({}, [10, 20, 30])
foo.wxapply({}, [10, 20, 30])
// // 配列のフラット化
// function flatten(arr) {
// return arr.reduce((pre, cur) => {
// return pre.concat(Array.isArray(cur) ? flatten(cur) : cur)
// }, [])
// }
// // バブルソート
function bubbleSort(arr) {
var len = arr.length
for (var i = 0; i < len; i++) {
for (var j = 0; j < len - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
var temp = arr[j]
arr[j] = arr[j + 1]
arr[j + 1] = temp
}
}
}
return arr
}
const arr = [1,9,2,8,3,7,4,6]
function fn(arr) {
const tem = []
for (let i = 0; i < arr.length; i++) {
if (arr[i] < arr[i + 1]) {
tem.push(arr[i])
}else{
let tem = arr[i]
arr[i] = arr[i + 1]
arr[i + 1] = tem
}
}
return tem
}
console.log(fn(arr))
// 発行購読モデル
function Event() {
this.handlers = []
}
Event.prototype.addHandler = function (handler) {
this.handlers.push(handler)
}
Event.prototype.removeHandler = function (handler) {
this.handlers = this.handlers.filter(item => item !== handler)
}
Event.prototype.fire = function (sender, args) {
this.handlers.forEach(item => item(sender, args))
}
// **HTTPの一般的なステータスコードとその意味**
// 200 OK
// 201 Created
// 202 Accepted
// 203 Non-Authoritative Information
// 204 No Content
// 205 Reset Content
// 206 Partial Content
// 300 Multiple Choices
// 301 Moved Permanently
// 302 Found
// 303 See Other
// 304 Not Modified
// 305 Use Proxy
// 307 Temporary Redirect
// 400 Bad Request
// 401 Unauthorized
// 402 Payment Required
// 403 Forbidden
// 404 Not Found
// 405 Method Not Allowed
// 406 Not Acceptable
// 407 Proxy Authentication Required
// 408 Request Timeout
// 409 Conflict
// 410 Gone
// 411 Length Required
// 412 Precondition Failed
// 413 Request Entity Too Large
// 414 Request-URI Too Long
// 415 Unsupported Media Type
// 416 Requested Range Not Satisfiable
// 417 Expectation Failed
// 500 Internal Server Error
// 501 Not Implemented
// 502 Bad Gateway
// 503 Service Unavailable
// 504 Gateway Timeout
// 505 HTTP Version Not Supported
// HTTPにはどのようなリクエストメソッドがあり、GETとPOSTの違いは何ですか
// GET:クエリ
// POST:送信
// PUT:更新
// DELETE:削除
// HEAD:リクエストヘッダー
// OPTIONS:リクエストオプション
// TRACE:リクエストトレース
// CONNECT:リクエスト接続
// PATCH:リクエスト補充
//GETとPOSTの違い
// HTTPプロトコルのヘッダーとその意味
// Accept:クライアントが受け入れることができるコンテンツタイプ
// Accept-Charset:クライアントが受け入れることができる文字セット
// Accept-Encoding:クライアントが受け入れることができるエンコーディング方式
// Accept-Language:クライアントが受け入れることができる言語
// Authorization:認証情報
// Cache-Control:キャッシュ制御
// Connection:接続方式
// Cookie:Cookie情報
// Content-Length:コンテンツの長さ
// Content-Type:コンテンツタイプ
// Date:日付
// Expect:期待
// From:出所
// Host:ホスト
// If-Match:一致する場合
// If-Modified-Since:変更された場合
// If-None-Match:一致しない場合
// If-Range:範囲の場合
// If-Unmodified-Since:未変更の場合
// Max-Forwards:最大転送数
// Pragma:短いリクエストヘッダー
// Proxy-Authorization:プロキシ認証
// Range:範囲
// Referer:出所
// TE:転送エンコーディング
// Upgrade:アップグレード
// User-Agent:ユーザーエージェント
// Via:経由
// Warning:警告
// X-Requested-With:リクエストタイプ
// X-Forwarded-For:転送されたクライアントIP
// X-Forwarded-Host:転送されたクライアントホスト
// X-Forwarded-Server:転送されたサーバー
// X-Frame-Options:フレーム設定
// X-XSS-Protection:XSS保護
// X-Content-Type-Options:コンテンツタイプ設定
// X-Powered-By:サーバー提供
// X-UA-Compatible:ブラウザ互換性
// URLを入力してEnterキーを押すときに何が起こるか
// 1. クライアントがリクエストを送信
// 2. サーバーがリクエストを受信
// 3. サーバーがリクエストに基づいて処理を行う
// 4. サーバーが応答を返す
// 5. クライアントが応答を受信
// **ブラウザのイベント伝達メカニズムの原理**
// ブラウザでは、イベント伝達メカニズムはイベントバブリングの方法で実現されます。イベントバブリングは、最近の要素から最も遠い要素までの順に、各要素がイベントをトリガーします。イベントのトリガーは、イベントバブリングの方法で実現されます。
instanceof の実装#
function isPrototypeOf(obj) {
var proto = this.prototype
while (obj) {
if (obj === proto) {
return true
}
obj = Object.getPrototypeOf(obj)
}
return false
}
イテラブルオブジェクト#
// このオブジェクトはイテレータを返します
const iterabalObj = {
names : ['Tom','Sily','Lusy'],
// イテラブルオブジェクトは[Symbol.iterator]というプロパティを持ち、その関数がイテレータを返す必要があります
[Symbol.iterator]:function(){
let index = 0
return {
next:()=>{
if(index < this.names.length){
return { done:false, value:this.names[index++]}
}else{
return { done:true, value:undefined}
}
}
}
}
}
console.log(iterabalObj[Symbol.iterator]); //[Function: [Symbol.iterator]]
// この関数を呼び出すと新しいイテレータが生成されます
const iterator = iterabalObj[Symbol.iterator]()
console.log(iterator.next()); //{ done: false, value: 'Tom' }
console.log(iterator.next()); //{ done: false, value: 'Sily' }
console.log(iterator.next()); //{ done: false, value: 'Lusy' }
// 新しいイテレータ
const iterator1 = iterabalObj[Symbol.iterator]()
console.log(iterator1.next()); //{ done: false, value: 'Tom' }
console.log(iterator1.next()); //{ done: false, value: 'Sily' }
console.log(iterator1.next()); //{ done: false, value: 'Lusy' }
for(const item of iterabalObj){
console.log(item);
// Tom
// Sily
// Lusy
}
オブジェクト操作の監視#
const obj = {
name:'Tom',
age:18
}
// Object.defineProperty(obj,'name',{
// get:function(){
// console.log('nameプロパティがアクセスされました');
// },
// set:function(){
// console.log('nameプロパティが設定されました');
// }
// })
// console.log(obj.name); //nameプロパティがアクセスされました
// obj.name = 'Kobe' //nameプロパティが設定されました
// オブジェクトのすべてのキーを取得できます
Object.keys(obj).forEach(key=>{
let value = obj[key]
console.log(key);
/* name
age
*/
Object.defineProperty(obj,key,{
get:function(){
console.log('プロパティがアクセスされました');
return value
},
set:function(newValue){
console.log('nameプロパティが設定されました');
}
})
})
console.log(obj.name); //nameプロパティがアクセスされました
obj.name = 'Kobe' //nameプロパティが設定されました
反応性の原理#
class Depend {
constructor(){
this.reactiveFns = []
}
// 依存関係を収集
addDepend(reactiveFn){
this.reactiveFns.push(reactiveFn)
}
// 依存関係を実行
notify(){
// すべての依存関係をループして実行
this.reactiveFns.forEach(fn => {
fn()
})
}
}
const depend = new Depend()
const obj = {
name:'Tom',
age:18
}
// プロキシやObject.definePropertyを使ってプロパティの変化を監視し、depend.notify()を実行
const objProxy = new Proxy(obj,{
get:function(target,key,receiver){
// 値を取得して返す
return Reflect.get(target,key,receiver)
},
// プロキシオブジェクトに値を設定するときに自動的にこのメソッドが実行されます
set:function(target,key,newvalue,receiver){
Reflect.set(target,key,newvalue,receiver)
// 値を設定するときにdependに通知して依存関係を実行
depend.notify()
}
})
function foo(){
console.log('コードを実行');
}
depend.addDepend(foo) //依存関係を収集
objProxy.name = 'Lilei'
イテレータ#
//イテレータは以下の条件を満たす必要があります
// 一、オブジェクトであること
// 二、オブジェクトにnextメソッドがあること
// 三、そのメソッドがオブジェクトを返し、そのオブジェクトにはdoneとvalueプロパティがあること
// const iterator = {
// next: function () {
// return { done: true, value: "" };
// },
// };
// 配列
const arr = ['abc','cba','nba']
// イテレータを使って配列を走査
// 配列にアクセスするためのイテレータオブジェクトを作成
let index = 0
const arrIterator = {
next:function(){
if(index < arr.length){
return { done:false, value:arr[index++]}
}else{
return { done:true, value:undefined }
}
}
}
console.log(index); //0
console.log(arrIterator.next()); //{ done: false, value: 'abc' }
console.log(index); //1
console.log(arrIterator.next()); //{ done: false, value: 'cba' }
console.log(index); //2
console.log(arrIterator.next()); //{ done: false, value: 'nba' }
console.log(index); //3
console.log(arrIterator.next()); //{ done: true, value: undefined }
console.log(index); //3
// イテレータの最適化
カスタムクラスのイテラブル性#
// カスタムイテレータクラス
class Clasroom {
constructor(address, name, students) {
this.address = address;
this.name = name;
this.students = students;
}
entry(newStudents) {
this.students.push(newStudents);
}
[Symbol.iterator]() {
// この関数はイテレータを返します
let index = 0;
return {
next: () => {
if (index < this.students.length) {
return { done: false, value: this.students[index++] };
} else {
return { done: true, value: undefined };
}
},
};
}
}
const classroom = new Clasroom("北京市", "一小", ["tom", "sily", "kobe"]);
for (item of classroom) {
console.log(item);
// tom
// sily
// kobe
}
内蔵のイテラブルオブジェクトの作成#
const names = ['abc','cba','nba']
console.log(names[Symbol.iterator]); //[Function: values]
const iterator = names[Symbol.iterator]() //この関数を実行するとイテレータが返されます
console.log(iterator.next()); //{ value: 'abc', done: false }
console.log(iterator.next()); //{ value: 'cba', done: false }
console.log(iterator.next()); //{ value: 'nba', done: false }
console.log(iterator.next()); //{ value: undefined, done: true }
ジェネレーターの引数問題#
// 各コードブロックの引数問題
function* foo() {
console.log(1);
// 2回目のnext関数の実行時に渡された引数は、最初のyieldの返り値に代入されます
const n = yield
// 2番目のコードブロックは2回目のnextの実行時に実行されます
console.log(2 * n); // 20
yield '返り値 :console.log(Generator.next()) // 返り値 ......'
console.log(3);
yield
console.log(4);
}
const Generator = foo()
Generator.next()
Generator.next(10)
// Generator.next()を2回実行します
// 2回目の実行時に引数が渡されます
// この引数は最初のyieldの返り値として使用され、const n = yieldでnを使用してその返り値を受け取ります
ジェネレーター関数の実行フロー#
function* foo() {
console.log(1);
yield '返り値' //このコードブロックの返り値
console.log(2);
yield
console.log(3);
yield
console.log(4);
}
const Generator = foo()
// 返り値はvalue ,done:false
console.log(Generator.next()); // { value: { name: 'tom', age: 18 }, done: false }
// Generator.next() // 1
// ジェネレーター関数 function*
// yieldキーワードはコードをここで一時停止させることができます
// ジェネレーター関数を実行すると、ジェネレーターオブジェクトが返されます
// このジェネレーターオブジェクトのnextメソッドを呼び出すと、yieldの前のコードが順に実行されます
// 再度next()を呼び出すと、次のyieldの前のコードが続けて実行されます
// 各yieldの前のコードが何らかの値を返したい場合は、その返り値をyieldの後に書くことができます
Proxy トラップの使用#
const obj = {
name: "Tom",
age: 18,
height: 1.88,
};
// プロキシを作成
// パラメータ1:objオブジェクトを代理 パラメータ2:トラップ(13種類のトラップがあります)
const objProxy = new Proxy(obj, {
// 値を取得するトラップ(値を取得するときに自動的にこの関数がコールバックされます)
get:function(target,key){
console.log(target);
console.log(key);
return target[key]
},
// 値を設定するトラップ(値を設定するときに自動的にこの関数がコールバックされます)
set:function(target,key,newValue){
target[key] = newValue
},
// inトラップを監視
has:function(target,key){
console.log('in演算子が使用されました');
return key in target
},
// deleteトラップを監視
deleteProperty:function(target,key){
console.log('プロパティが削除されました');
delete target[key]
}
});
// console.log(objProxy.name); // Kobe
// console.log('name' in objProxy); // true
delete objProxy.name
プロトタイプ#
function Fn() {
}
Fn.prototype = {
name: 'Tom',
age: 18
}
const p1 = new Fn()
const p2 = new Fn()
console.log(p1.name);
console.log(p2.name);
console.log(p2.toString());
配列の重複排除#
const unique = (arr) => {
if(!Array.isArray(arr)){
return console.error('パラメータは配列でなければなりません')
}
const temArr = []
for(let i = 0; i < arr.length; i++){
if(temArr.indexOf(arr[i]) === -1){
temArr.push(arr[i])
}
// OR
// if(temArr.includes(arr[i])){
// temArr.push(arr[i])
// }
}
return temArr.sort()
}
const result = unique([1,1,1,2,3,2,3,4,5,6,4,2,9,8,7,8,7,6])
console.log(result);
console.log(typeof 3..toString());
// 3 ===> 0000 0011 ===> 0000 1100
console.log(3 << 2);