关于 this
在绝大多数情况下,函数的挪用体式格局决议了this的值。this不能在实行时期被赋值,并且在每次函数被挪用时this的值也可能会差别。
全局 this
window.something = 'I love JavaScript'
console.log(this.something) // 'I love JavaScript'
console.log(window === this) // true
挪用全局 function
var a = 1
function test() { console.log(this.a) }
test() // 1 - still remains the window reference
挪用对象中的 function
this.a = 'I am in the global scope'
function Test() {
this.a = 'I am in the test scope'
this.show = function() { console.log(this.a) }
}
Test.prototype.display = function () { console.log(this.a) }
var test = new Test() // updated the scope of this
test.show() // I am in the test scope
test.display() // I am in the test scope
关于 call / apply
JavaScript 内部供应了一种机制,让我们能够自行手动设置 this 的指向。它们就是 call 与 apply。一切的函数都具有着两个要领。它们除了参数略有差别,其功用完整一样。它们的第一个参数都为 this 将要指向的对象。
一个最简朴的继续
function Laptop(name, storage) {
this.name = name
this.storage = storage
}
function Dell(name, storage, company) {
Laptop.call(this, 'Dell', 1024)
this.company = company
}
console.log(new Dell('Dell', 1024, 'Dell Inc').storage)
转变 this
var obj = {
entry: 'mammals-banana-tower',
duration: 0
}
function breed(name) {
console.log('Show this breeding info', name, this.entry, this.duration)
console.log(this === obj)
}
breed() // this => window
breed.call(obj, 'Frank') // this => obj
注:当没有通报任何参数作为 call() 的第一个参数时,在非严厉形式下,this 会指向 window。
完成一个简朴的 call
var _call = function (that) {
that = that ? Object(that) : window
that.func = this
function formatArgs(oArgs, sign) {
var _args
for (var i = 1, len = oArgs.length; i < len; i++) {
_args.push(sign ? ('_param_' + i) : oArgs[i])
}
return _args
}
var args = formatArgs(arguments)
var newFunc = (new Function('args', 'return that.func(' + formatArgs(args, true).toString() + ')'))(args)
that.func = null
return newFunc
}
关于 bind
() => {} 和 bind this
用过 React 的同砚都晓得,当运用 class component 时,须要在 constructor 绑定当前的成员函数,或许针对事宜托付的情况下,也须要举行绑定;ES6 箭头函数能够让我们更专注于详细的完成逻辑,简化了 this 操纵
// ES5
// <a onclick={this.handleClick.bind(this)}></a>
// constructor() { this.handleClick = this.handleClick.bind(this) }
// ES6
// <a onclick={() => handleClick()}></a>
// handleClick = () => {}
无效的 re-bound
var f = function() { console.log(this.text) }
f = f.bind({ text: 'I was bound' }).bind({ text: 'I won't be bound' })
f() // I was bound
很轻易发明,f.bind() 返回的绑定函数对象仅在建立是保存当前的上下文(或许传入的参数),因而没法在第二次举行重绑定。
一个相对完美的 bind
var _bind = function (that) {
var fBound,
target = this,
slice = Array.prototype.slice,
toStr = Object.prototype.toString,
args = slice.call(arguments, 1); // except that
if (typeof target !== 'function' || toStr.call(target) !== '[object Function]') {
throw new TypeError('Function.prototype.bind - what is trying to be bound is not callable');
}
var binder = function () {
var oArgs = args.concat(slice.call(arguments))
if (this instanceof fBound) {
var result = target.apply(this, oArgs);
return Object(result) === result ? result : this;
} else {
return target.apply(that, oArgs);
}
};
var i = 0,
params = [],
paramLength = Math.max(0, target.length - args.length);
for (; i < paramLength; i++) {
params.push('_param_' + i);
}
fBound = (new Function(
'binder',
'return function(' + params.join(',') + ') { return binder.apply(this,arguments); }'
))(binder);
// maintain the reference of prototype
if (target.prototype) {
var fNOP = function () { };
fNOP.prototype = target.prototype;
fBound.prototype = new fNOP();
fNOP.prototype = null;
}
return fBound;
};
参考
https://developer.mozilla.org…
https://developer.mozilla.org…
https://developer.mozilla.org…
https://developer.mozilla.org…
https://developer.mozilla.org…
https://developer.mozilla.org…
https://www.ecma-internationa…
https://javascript.info/bind
https://juejin.im/post/5c0605…
https://github.com/mqyqingfen…