在絕大多數狀況下,函數的調用方式決定了this的值。this不能在執行期間被賦值,而且在每次函數被調用時this的值也可能會不一樣。javascript
window.something = 'I love JavaScript' console.log(this.something) // 'I love JavaScript' console.log(window === this) // true
var a = 1 function test() { console.log(this.a) } test() // 1 - still remains the window reference
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
JavaScript 內部提供了一種機制,讓咱們能夠自行手動設置 this 的指向。它們就是 call 與 apply。全部的函數都具備着兩個方法。它們除了參數略有不一樣,其功能徹底同樣。它們的第一個參數都爲 this 將要指向的對象。java
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)
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。git
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 }
用過 React 的同窗都知道,當使用 class component 時,須要在 constructor 綁定當前的成員函數,或者針對事件委託的狀況下,也須要進行綁定;ES6 箭頭函數能夠讓咱們更專一於具體的實現邏輯,簡化了 this 操做github
// ES5 // <a onclick={this.handleClick.bind(this)}></a> // constructor() { this.handleClick = this.handleClick.bind(this) } // ES6 // <a onclick={() => handleClick()}></a> // handleClick = () => {}
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() 返回的綁定函數對象僅在建立是保留當前的上下文(或者傳入的參數),所以沒法在第二次進行重綁定。app
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...函數