基本構文
funのthisはArgオブジェクトのthisを指します。
fun.call(thisArg, param1, param2, ...)
fun.apply(thisArg, [param1,param2,...])
fun.bind(thisArg, param1, param2, ...)
連想記憶:最初の'a'はArrayを表します。
戻り値
call/apply: funの実行結果、つまり関数のコンテキストが変更され、関数が即座に実行されます bind: funのコピーが、指定された this値と初期パラメータで返されます。
コアコンセプト:借りた手法
アプリケーションシナリオ
- 判定の種類
Object.prototype.toString.call(data)
ほぼすべての種類のデータの決定に手を貸すことができます。
'[object String]': 'string',
'[object Number]': 'number',
'[object Boolean]': 'boolean',
'[object Null]': 'null',
'[object Undefined]': 'undefined',
'[object Object]': 'object',
'[object Array]': 'array',
'[object Function]': 'function',
'[object Date]': 'date', // Object.prototype.toString.call(new Date())
'[object RegExp]': 'regExp',
'[object Map]': 'map',
'[object Set]': 'set',
'[object HTMLDivElement]': 'dom', // document.querySelector('#app')
'[object WeakMap]': 'weakMap',
'[object Window]': 'window', // Object.prototype.toString.call(window)
'[object Error]': 'error', // new Error('1')
'[object Arguments]': 'arguments'
- クラス配列は配列からメソッドを借用します。
var arrayLike = {
0: 'OB',
1: 'Koro1',
length: 2
}
Array.prototype.push.call(arrayLike, '要素を追加する。1', '要素を追加する。2');
console.log(arrayLike) // {"0":"OB","1":"Koro1","2":"要素を追加する。1","3":"要素を追加する。2","length":4}
- は、配列の最大値と最小値を取得します。
const arr = [, 13, 16];
const max = Math.max.apply(Math, arr); // 16
const min = Math.min.apply(Math, arr); // 6
- 親クラスのコンストラクタ・メソッドを借りて、親クラスのメソッドやプロパティを継承します。
//
function supFather(name) {
this.name = name;
this.colors = ['red', 'blue', 'green']; // 複合型
}
function sub(name, age) {
// 親クラスからメソッドを借りる:thisポインタを修正し、親のコンストラクタのメソッドとプロパティを子クラスに割り当てる。
supFather.call(this, name);
this.age = age;
}
- バインドの応用シナリオ
. 変数の保存
for (var i = 1; i <= 5; i++) {
// キャッシュされたパラメータ
setTimeout(function (i) {
console.log('bind', i) // 順番に出力する:1 2 3 4 5
}.bind(null, i), i * 1000);
}
bindは関数を返すので、この関数はクロージャとも呼ばれます。
this "コールバック関数の欠落の解消
this.pageClass = new Page(this.handleMessage.bind(this)) // を指すようにコールバック関数のthisをバインドする。
call,apply,bind
コールの実装
Function.prototype.myCall = function (context, ...args) {
if (context === null || context === undefined) {
context = window;
} else {
// この値は元の値のインスタンスを指す。
context = Object(context);
}
const specialPrototype = Symbol('の特別な属性はSymbol');
context[specialPrototype] = this; // この場合、これはメソッドを呼び出した関数自身を指し、関数内部のこれはcontext
let result = context[specialPrototype](...args); // 暗黙のバインディングによって関数を実行し、引数を渡す。
delete context[specialPrototype];
return result;
}
applyの実装は、callと比較して、入力されたパラメーターの判定を追加するだけです。
Function.prototype.myApply = function (context) {
if (context === null || context === undefined) {
context = window;
} else {
// この値は元の値のインスタンスを指す。
context = Object(context);
}
const isArrayLike = (o) => {
if (o && // onull、undefinedなどではない。
typeof o === 'object' && // o
isFinite(o.length) && // o.lengthは有限の値である
o.length >= 0 && // o.lengthは負でない値である
o.length === Math.floor(o.length) && // o.length
o.length < ) // o.length < 2^32
return true
else
return false
};
const specialPrototype = Symbol('の特別な属性はSymbol');
context[specialPrototype] = this;
let args = arguments[1]; // パラメータの配列を取得する。
let result;
if (args) {
if (!Array.isArray(args) && !isArrayLike(args)) {
throw new TypeError('myApply 第2引数が配列でなく、配列のようなオブジェクトでもない場合はエラーを投げる。');
} else {
args = Array.from(args);
result = context[specialPrototype](...args);
}
} else {
result = context[specialPrototype]();
}
delete context[specialPrototype];
return result;
}
バインドの実装
Function.prototype.myBind = function (thisObj, ...args) {
const thisFn = this; // ソース関数を格納する
let fToBind = function (...secondArgs) {
const isNew = this instanceof fToBind; // thisfToBindのインスタンスであるかどうか つまり、返されたfToBindがnewによって呼び出されるかどうかである。
const context = isNew ? this: Object(thisObj); // new呼び出されたらこれにバインドし、そうでなければ、入力されたthisObjにバインドする。
return thisFn.call(context, ...args, ...secondArgs); // これをバインドするコールとパラメータを渡すコールでソース関数を呼び出し、結果を返す。
};
fToBind.prototype = Object.create(thisFn.prototype); // ソース関数のプロトタイプをfToBind
return fToBind;
}





