参考连接:
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);