參考連接:
https://github.com/jawil/blog...javascript
在 JavaScript 中,this 是指當前函數中正在執行的上下文環境:java
函數調用 表明了該函數接收以成對的引號包含,用逗號分隔的不一樣參數組成的表達式。git
function sum(a, b) { console.log(this === window); // => true this.myNumber = 20; // 在全局對象中添加 'myNumber' 屬性 return a + b; } // sum() 爲函數調用 // this 在 sum() 中是全局對象 (window) sum(15, 16); // => 31 window.myNumber; // => 20
當 sum(15, 16) 被調用時,JavaScript 自動將 this 設置爲全局對象,即 window。github
嚴格模式由 ECMAScript 5.1 引進,用來限制 JavaScript 的一些異常處理,提供更好的安全性和更強壯的錯誤檢查機制。使用嚴格模式,只須要將 'use strict' 置於函數體的頂部。這樣就能夠將上下文環境中的 this 轉爲 undefined。這樣執行上下文環境再也不是全局對象,與非嚴格模式恰好相反。數組
function multiply(a, b) { 'use strict'; // 開啓嚴格模式 console.log(this === undefined); // => true return a * b; } // 嚴格模式下的函數調用 multiply() // this 在 multiply() 中爲 undefined multiply(2, 5); // => 10
嚴格模式不只在當前做用域起到做用,它還會影響內部做用域,即內部聲明的一切內部函數的做用域。安全
function execute() { 'use strict'; // 開啓嚴格模式 function concat(str1, str2) { // 內部函數也是嚴格模式 console.log(this === undefined); // => true return str1 + str2; } // 在嚴格模式下調用 concat() // this 在 concat() 下是 undefined concat('Hello', ' World!'); // => "Hello World!" } execute();
當在一個對象裏調用方法時,this 表明的是對象它自身。
嚴格模式不只在當前做用域起到做用,它還會影響內部做用域,即內部聲明的一切內部函數的做用域。app
var calc = { num: 0, increment: function() { console.log(this === calc); // => true this.num += 1; return this.num; } }; // 方法調用,this 指向 calc calc.increment(); // => 1 calc.increment(); // => 2
function Foo () { console.log(this instanceof Foo); // => true this.property = 'Default Value'; } // 構造函數調用 var fooInstance = new Foo(); fooInstance.property; // => 'Default Value'
間接調用表現爲當一個函數使用了 .call() 或者 .apply() 方法。.call() 和 .apply() 被用來配置當前調用的上下文環境。函數
var rabbit = { name: 'White Rabbit' }; function concatName(string) { console.log(this === rabbit); // => true return string + this.name; } // 間接調用 concatName.call(rabbit, 'Hello '); // => 'Hello White Rabbit' concatName.apply(rabbit, ['Bye ']); // => 'Bye White Rabbit'
兩個方法最主要的區別爲 .call() 接收一組參數,而 .apply() 接收一串參數做爲類數組對象傳遞。
綁定函數調用是將函數綁定一個對象,它是一個原始函數使用了 .bind() 方法。this
方法 .bind(thisArg[, arg1[, arg2[, ...]]]) 接收第一個參數 thisArg 做爲綁定函數在執行時的上下文環境,以及一組參數 arg1, arg2, ... 做爲傳參傳入函數中。 它返回一個新的函數,綁定了 thisArg。
function multiply(number) { 'use strict'; return this * number; } // 建立綁定函數,綁定上下文2 var double = multiply.bind(2); // 調用間接調用 double(3); // => 6 double(10); // => 20
var numbers = { array: [3, 5, 10], getNumbers: function() { return this.array; } }; // 建立一個綁定函數 var boundGetNumbers = numbers.getNumbers.bind(numbers); boundGetNumbers(); // => [3, 5, 10] // 從對象中抽取方法 var simpleGetNumbers = numbers.getNumbers; simpleGetNumbers(); // => undefined 或者嚴格模式下拋出錯誤
.bind() 建立了一個永恆的上下文鏈並不可修改。一個綁定函數即便使用 .call() 或者 .apply()傳入其餘不一樣的上下文環境,也不會更改它以前鏈接的上下文環境,從新綁定也不會起任何做用。
function getThis() { 'use strict'; return this; } var one = getThis.bind(1); // 綁定函數調用 one(); // => 1 // 使用 .apply() 和 .call() 綁定函數 one.call(2); // => 1 one.apply(2); // => 1 // 從新綁定 one.bind(2)(); // => 1 // 利用構造器方式調用綁定函數 new one(); // => Object
補充bind用法
bind()的另外一個最簡單的用法是使一個函數擁有預設的初始參數。這些參數(若是有的話)做爲bind()的第二個參數跟在this(或其餘對象)後面,以後它們會被插入到目標函數的參數列表的開始位置,傳遞給綁定函數的參數會跟在它們的後面。
function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, 2, 3] // Create a function with a preset leading argument var leadingThirtysevenList = list.bind(undefined, 37); var list2 = leadingThirtysevenList(); // [37] var list3 = leadingThirtysevenList(1, 2, 3); // [37, 1, 2, 3]
箭頭函數的設計意圖是以精簡的方式建立函數,並綁定定義時的上下文環境。prototype
箭頭函數並不建立它自身執行的上下文,使得 this 取決於它在定義時的外部函數。
class Point { constructor(x, y) { this.x = x; this.y = y; } log() { console.log(this === myPoint); // => true setTimeout(()=> { console.log(this === myPoint); // => true console.log(this.x + ':' + this.y); // => '95:165' }, 1000); } } var myPoint = new Point(95, 165); myPoint.log();
箭頭函數一次綁定上下文後便不可更改,即便使用了上下文更改的方法.
var numbers = [1, 2]; (function() { var get = () => { console.log(this === numbers); // => true return this; }; console.log(this === numbers); // => true get(); // => [1, 2] // 箭頭函數使用 .apply() 和 .call() get.call([0]); // => [1, 2] get.apply([0]); // => [1, 2] // Bind get.bind([0])(); // => [1, 2] }).call(numbers);
var numbers = { numberA: 5, numberB: 10, sum: function() { console.log(this === numbers); // => true function calculate() { console.log(this === numbers); // => false return this.numberA + this.numberB; } return calculate(); } }; numbers.sum();
解決辦法:return calculate.call(this);
function Animal(type, legs) { this.type = type; this.legs = legs; this.logInfo = function() { console.log(this === myCat); // => false console.log('The ' + this.type + ' has ' + this.legs + ' legs'); } } var myCat = new Animal('Cat', 4); setTimeout(myCat.logInfo, 1000);
解決辦法:setTimeout(myCat.logInfo.bind(myCat), 1000);
var name = "aa"; var user = { name: 'hhh', sayName: function(){ console.log(this.name); } } var test = user.sayName; test(); // aa
解決辦法:var test = user.sayName.bind(user);