å½å°å¯¹è±¡æ¹æ³ä½ä¸ºåè°è¿è¡ä¼ éï¼ä¾å¦ä¼ éç» setTimeoutï¼è¿å¿ä¼åå¨ä¸ä¸ªå¸¸è§çé®é¢ï¼â丢失 thisâã
卿¬ç« ä¸ï¼æä»¬ä¼å¦ä¹ å¦ä½å»è§£å³è¿ä¸ªé®é¢ã
丢失 âthisâ
æä»¬å·²ç»çå°äºä¸¢å¤± this çä¾åã䏿¦æ¹æ³è¢«ä¼ éå°ä¸å¯¹è±¡åå¼çæä¸ªå°æ¹ ââ this 就丢失ã
ä¸é¢æ¯ä½¿ç¨ setTimeout æ¶ this æ¯å¦ä½ä¸¢å¤±çï¼
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(user.sayHi, 1000); // Hello, undefined!
æ£å¦æä»¬æçå°çï¼è¾åºæ²¡æå this.firstName 飿 ·æ¾ç¤º âJohnâï¼èæ¾ç¤ºäº undefinedï¼
è¿æ¯å 为 setTimeout è·åå°äºå½æ° user.sayHiï¼ä½å®å对象å离å¼äºãæåä¸è¡å¯ä»¥è¢«éå为ï¼
let f = user.sayHi;
setTimeout(f, 1000); // ä¸¢å¤±äº user ä¸ä¸æ
æµè§å¨ä¸ç setTimeout æ¹æ³æäºç¹æ®ï¼å®ä¸ºå½æ°è°ç¨è®¾å®äº this=windowï¼å¯¹äº Node.jsï¼this åä¼å为计æ¶å¨ï¼timerï¼å¯¹è±¡ï¼ä½å¨è¿å¿å¹¶ä¸éè¦ï¼ãæä»¥å¯¹äº this.firstNameï¼å®å
¶å®è¯å¾è·åçæ¯ window.firstNameï¼è¿ä¸ªåéå¹¶ä¸åå¨ãå¨å
¶ä»ç±»ä¼¼çæ
åµä¸ï¼é常 this ä¼å为 undefinedã
è¿ä¸ªéæ±å¾å ¸å ââ æä»¬æ³å°ä¸ä¸ªå¯¹è±¡æ¹æ³ä¼ éå°å«çå°æ¹ï¼è¿é ââ ä¼ éå°è°åº¦ç¨åºï¼ï¼ç¶åå¨è¯¥ä½ç½®è°ç¨å®ãå¦ä½ç¡®ä¿å¨æ£ç¡®çä¸ä¸æä¸è°ç¨å®ï¼
è§£å³æ¹æ¡ 1ï¼å è£ å¨
æç®åçè§£å³æ¹æ¡æ¯ä½¿ç¨ä¸ä¸ªå è£ å½æ°ï¼
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(function() {
user.sayHi(); // Hello, John!
}, 1000);
ç°å¨å®å¯ä»¥æ£å¸¸å·¥ä½äºï¼å 为å®ä»å¤é¨è¯æ³ç¯å¢ä¸è·åå°äº userï¼å°±å¯ä»¥æ£å¸¸å°è°ç¨æ¹æ³äºã
ç¸åçåè½ï¼ä½æ¯æ´ç®çï¼
setTimeout(() => user.sayHi(), 1000); // Hello, John!
çèµ·æ¥ä¸éï¼ä½æ¯æä»¬ç代ç ç»æä¸åºç°äºä¸ä¸ªå°æ¼æ´ã
å¦æå¨ setTimeout 触åä¹åï¼æä¸ç§çå»¶è¿ï¼ï¼user ç弿¹åäºæä¹åï¼é£ä¹ï¼çªç¶é´ï¼å®å°è°ç¨é误ç对象ï¼
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
setTimeout(() => user.sayHi(), 1000);
// â¦â¦user çå¼å¨ä¸å° 1 ç§çæ¶é´å
åçäºæ¹å
user = {
sayHi() { alert("Another user in setTimeout!"); }
};
// Another user in setTimeout!
ä¸ä¸ä¸ªè§£å³æ¹æ¡ä¿è¯äºè¿æ ·çäºæ ä¸ä¼åçã
è§£å³æ¹æ¡ 2ï¼bind
彿°æä¾äºä¸ä¸ªå
å»ºæ¹æ³ bindï¼å®å¯ä»¥ç»å® thisã
åºæ¬çè¯æ³æ¯ï¼
// ç¨åå°ä¼ææ´å¤æçè¯æ³
let boundFunc = func.bind(context);
func.bind(context) çç»ææ¯ä¸ä¸ªç¹æ®ç类似äºå½æ°çâ夿¥å¯¹è±¡ï¼exotic objectï¼âï¼å®å¯ä»¥å彿°ä¸æ ·è¢«è°ç¨ï¼å¹¶ä¸éæå°ï¼transparentlyï¼å°è°ç¨ä¼ éç» func å¹¶è®¾å® this=contextã
æ¢å¥è¯è¯´ï¼boundFunc è°ç¨å°±åç»å®äº this ç funcã
举个ä¾åï¼è¿éç funcUser å°è°ç¨ä¼ éç»äº func åæ¶ this=userï¼
let user = {
firstName: "John"
};
function func() {
alert(this.firstName);
}
let funcUser = func.bind(user);
funcUser(); // John
è¿éç func.bind(user) ä½ä¸º func çâç»å®çï¼boundï¼åä½âï¼ç»å®äº this=userã
ææçåæ°ï¼argumentsï¼é½è¢«âåæ ·âä¼ éç»äºåå§ç funcï¼ä¾å¦ï¼
let user = {
firstName: "John"
};
function func(phrase) {
alert(phrase + ', ' + this.firstName);
}
// å° this ç»å®å° user
let funcUser = func.bind(user);
funcUser("Hello"); // Hello, Johnï¼åæ° "Hello" è¢«ä¼ éï¼å¹¶ä¸ this=userï¼
ç°å¨æä»¬æ¥å°è¯ä¸ä¸ªå¯¹è±¡æ¹æ³ï¼
let user = {
firstName: "John",
sayHi() {
alert(`Hello, ${this.firstName}!`);
}
};
let sayHi = user.sayHi.bind(user); // (*)
// å¯ä»¥å¨æ²¡æå¯¹è±¡ï¼è¯æ³¨ï¼ä¸å¯¹è±¡å离ï¼çæ
åµä¸è¿è¡å®
sayHi(); // Hello, John!
setTimeout(sayHi, 1000); // Hello, John!
// å³ä½¿ user çå¼å¨ä¸å° 1 ç§å
åçäºæ¹å
// sayHi è¿æ¯ä¼ä½¿ç¨é¢å
ç»å®ï¼pre-boundï¼çå¼ï¼è¯¥å¼æ¯å¯¹æ§ç user 对象çå¼ç¨
user = {
sayHi() { alert("Another user in setTimeout!"); }
};
å¨ (*) è¡ï¼æä»¬åäºæ¹æ³ user.sayHi å¹¶å°å
¶ç»å®å° userãsayHi æ¯ä¸ä¸ªâç»å®åï¼boundï¼âçæ¹æ³ï¼å®å¯ä»¥è¢«åç¬è°ç¨ï¼ä¹å¯ä»¥è¢«ä¼ éç» setTimeout ââ 齿²¡å
³ç³»ï¼å½æ°ä¸ä¸æé½ä¼æ¯æ£ç¡®çã
è¿éæä»¬è½å¤çå°åæ°ï¼argumentsï¼é½è¢«âåæ ·âä¼ éäºï¼åªæ¯ this 被 bind ç»å®äºï¼
let user = {
firstName: "John",
say(phrase) {
alert(`${phrase}, ${this.firstName}!`);
}
};
let say = user.say.bind(user);
say("Hello"); // Hello, John!ï¼åæ° "Hello" è¢«ä¼ éç»äº sayï¼
say("Bye"); // Bye, John!ï¼åæ° "Bye" è¢«ä¼ éç»äº sayï¼
bindAll妿ä¸ä¸ªå¯¹è±¡æå¾å¤æ¹æ³ï¼å¹¶ä¸æä»¬é½æç®å°å®ä»¬é½ä¼ éåºå»ï¼é£ä¹æä»¬å¯ä»¥å¨ä¸ä¸ªå¾ªç¯ä¸å®ææææ¹æ³çç»å®ï¼
for (let key in user) {
if (typeof user[key] == 'function') {
user[key] = user[key].bind(user);
}
}
JavaScript åºè¿æä¾äºæ¹ä¾¿æ¹éç»å®ç彿°ï¼ä¾å¦ lodash ä¸ç _.bindAll(object, methodNames)ã
é¨åï¼åºç¨ï¼å½æ°ï¼Partial functionsï¼
å°ç°å¨ä¸ºæ¢ï¼æä»¬åªå¨è°è®ºç»å® thisã让æä»¬åæ·±å
¥ä¸æ¥ã
æä»¬ä¸ä»
å¯ä»¥ç»å® thisï¼è¿å¯ä»¥ç»å®åæ°ï¼argumentsï¼ãè½ç¶å¾å°è¿ä¹åï¼ä½ææ¶å®å¯ä»¥æ´¾ä¸ç¨åºã
bind ç宿´è¯æ³å¦ä¸ï¼
let bound = func.bind(context, [arg1], [arg2], ...);
å®å
许å°ä¸ä¸æç»å®ä¸º thisï¼ä»¥åç»å®å½æ°çé¨ååæ°ã
ä¾å¦ï¼æä»¬æä¸ä¸ªä¹æ³å½æ° mul(a, b)ï¼
function mul(a, b) {
return a * b;
}
让æä»¬ä½¿ç¨ bind å¨è¯¥å½æ°åºç¡ä¸å建ä¸ä¸ª double 彿°ï¼
function mul(a, b) {
return a * b;
}
let double = mul.bind(null, 2);
alert( double(3) ); // = mul(2, 3) = 6
alert( double(4) ); // = mul(2, 4) = 8
alert( double(5) ); // = mul(2, 5) = 10
对 mul.bind(null, 2) çè°ç¨å建äºä¸ä¸ªæ°å½æ° doubleï¼å®å°è°ç¨ä¼ éå° mulï¼å° null ç»å®ä¸ºä¸ä¸æï¼å¹¶å° 2 ç»å®ä¸ºç¬¬ä¸ä¸ªåæ°ãå¹¶ä¸ï¼åæ°ï¼argumentsï¼å被âåæ ·âä¼ éã
å®è¢«ç§°ä¸º 彿°çé¨ååºç¨ï¼partial function applicationï¼ ââ æä»¬éè¿ç»å®å æå½æ°çä¸äºåæ°æ¥å建ä¸ä¸ªæ°å½æ°ã
请注æï¼è¿éæä»¬å®é
䏿²¡æç¨å° thisã使¯ bind éè¦å®ï¼æä»¥æä»¬å¿
é¡»ä¼ å
¥ null ä¹ç±»çä¸è¥¿ã
ä¸é¢è¿æ®µä»£ç ä¸ç triple 彿°å°å¼ä¹äºä¸åï¼
function mul(a, b) {
return a * b;
}
let triple = mul.bind(null, 3);
alert( triple(3) ); // = mul(3, 3) = 9
alert( triple(4) ); // = mul(3, 4) = 12
alert( triple(5) ); // = mul(3, 5) = 15
为ä»ä¹æä»¬é常ä¼å建ä¸ä¸ªé¨ååºç¨å½æ°ï¼
好夿¯æä»¬å¯ä»¥å建ä¸ä¸ªå
·æå¯è¯»æ§é«çååï¼doubleï¼tripleï¼çç¬ç«å½æ°ãæä»¬å¯ä»¥ä½¿ç¨å®ï¼å¹¶ä¸ä¸å¿
æ¯æ¬¡é½æä¾ä¸ä¸ªåæ°ï¼å ä¸ºåæ°æ¯è¢«ç»å®äºçã
å¦ä¸æ¹é¢ï¼å½æä»¬æä¸ä¸ªéå¸¸çµæ´»ç彿°ï¼å¹¶å¸ææä¸ä¸ªä¸é£ä¹çµæ´»çååæ¶ï¼é¨ååºç¨å½æ°ä¼é常æç¨ã
ä¾å¦ï¼æä»¬æä¸ä¸ªå½æ° send(from, to, text)ãç¶åï¼å¨ä¸ä¸ª user 对象çå
é¨ï¼æä»¬å¯è½å¸æå¯¹å®ä½¿ç¨ send çé¨ååºç¨å½æ°ååï¼ä»å½å user åé sendTo(to, text)ã
卿²¡æä¸ä¸ææ åµä¸ç partial
彿们æ³ç»å®ä¸äºåæ°ï¼argumentsï¼ï¼ä½æ¯ä¸æ³ç»å®ä¸ä¸æ thisï¼åºè¯¥æä¹åï¼ä¾å¦ï¼å¯¹äºä¸ä¸ªå¯¹è±¡æ¹æ³ã
åçç bind ä¸å
许è¿ç§æ
åµãæä»¬ä¸å¯ä»¥çç¥ä¸ä¸æç´æ¥è·³å°åæ°ï¼argumentsï¼ã
幸è¿çæ¯ï¼ä»
ç»å®åæ°ï¼argumentsï¼ç彿° partial æ¯è¾å®¹æå®ç°ã
åè¿æ ·ï¼
function partial(func, ...argsBound) {
return function(...args) { // (*)
return func.call(this, ...argsBound, ...args);
}
}
// ç¨æ³ï¼
let user = {
firstName: "John",
say(time, phrase) {
alert(`[${time}] ${this.firstName}: ${phrase}!`);
}
};
// æ·»å ä¸ä¸ªå¸¦æç»å®æ¶é´ç partial æ¹æ³
user.sayNow = partial(user.say, new Date().getHours() + ':' + new Date().getMinutes());
user.sayNow("Hello");
// 类似äºè¿æ ·çä¸äºå
容ï¼
// [10:00] John: Hello!
partial(func[, arg1, arg2...]) è°ç¨çç»ææ¯ä¸ä¸ªå
è£
å¨ (*)ï¼å®è°ç¨ func å¹¶å
·æä»¥ä¸å
容ï¼
- ä¸å®è·å¾ç彿°å
·æç¸åç
thisï¼å¯¹äºuser.sayNowè°ç¨æ¥è¯´ï¼å®æ¯userï¼ - ç¶åç»å®
...argsBoundââ æ¥èªäºpartialè°ç¨çåæ°ï¼"10:00"ï¼ - ç¶åç»å®
...argsââ ç»å è£ å¨çåæ°ï¼"Hello"ï¼
ä½¿ç¨ spread å¯ä»¥å¾å®¹æå®ç°è¿äºæä½ï¼å¯¹å§ï¼
æ¤å¤ï¼è¿ææ¥èª lodash åºçç°æç _.partial å®ç°ã
æ»ç»
æ¹æ³ func.bind(context, ...args) è¿å彿° func çâç»å®çï¼boundï¼åä½âï¼å®ç»å®äºä¸ä¸æ this å ...args åæ°ã
é常æä»¬åºç¨ bind æ¥ç»å®å¯¹è±¡æ¹æ³ç thisï¼è¿æ ·æä»¬å°±å¯ä»¥æå®ä»¬ä¼ éå°å
¶ä»å°æ¹ä½¿ç¨ãä¾å¦ï¼ä¼ éç» setTimeoutã
彿们ç»å®ä¸ä¸ªç°æç彿°çæäºåæ°æ¶ï¼ç»å®åçï¼ä¸å¤ªéç¨çï¼å½æ°è¢«ç§°ä¸º partially applied æ partialã
彿们䏿³ä¸éåä¸éå°éå¤ç¸åçåæ°æ¶ï¼é¨ååºç¨å½æ°é常æç¨ãå°±åæä»¬æä¸ä¸ª send(from, to) 彿°ï¼å¹¶ä¸å¯¹äºæä»¬ç任塿¥è¯´ï¼from åºè¯¥æ»æ¯ä¸æ ·çï¼é£ä¹æä»¬å°±å¯ä»¥ä½¿ç¨å®çä¸ä¸ªé¨ååºç¨å½æ°ã
è¯è®º
<code>æ ç¾æå ¥åªæå 个è¯ç代ç ï¼æå ¥å¤è¡ä»£ç å¯ä»¥ä½¿ç¨<pre>æ ç¾ï¼å¯¹äºè¶ è¿ 10 è¡ç代ç ï¼å»ºè®®ä½ ä½¿ç¨æ²ç®±ï¼plnkrï¼JSBinï¼codepenâ¦ï¼