关于 this在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。全局 thiswindow.something = ‘I love JavaScript’console.log(this.something) // ‘I love JavaScript’console.log(window === this) // true调用全局 functionvar a = 1function test() { console.log(this.a) }test() // 1 - still remains the window reference调用对象中的 functionthis.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 thistest.show() // I am in the test scopetest.display() // I am in the test scope 关于 call / applyJavaScript 内部提供了一种机制,让我们可以自行手动设置 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)改变 thisvar 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 => windowbreed.call(obj, ‘Frank’) // this => obj注:当没有传递任何参数作为 call() 的第一个参数时,在非严格模式下,this 会指向 window。实现一个简单的 callvar _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-boundvar 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() 返回的绑定函数对象仅在创建是保留当前的上下文(或者传入的参数),因此无法在第二次进行重绑定。一个相对完善的 bindvar _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/bindhttps://juejin.im/post/5c0605...https://github.com/mqyqingfen…
...