关于this的那些事
栏目: JavaScript · 发布时间: 6年前
内容简介:this表示关键字,也是一个常见的代词,经常来表示一个上下文对象,那上下文对象又是什么呢?上面代码我们主要关注一点就是执行上下文,在1、2的位置分别绑定me、you上下文对象,所以输出的是相对应的name值;在3位置前面定义了一个全局的name变量,并且在没有指定上下文环境被输出了,这也涉及到this的隐式绑定(在"this的绑定"讲会详细说明),绑定到了当前环境window。下面我们把`sayName`函数显式的传递上下文对象:
- 什么是this
- 词法作用域与动态作用域
- this的绑定
一、什么是this
this表示关键字,也是一个常见的代词,经常来表示一个上下文对象,那上下文对象又是什么呢?
var me = {
name: 'JJ Yu'
};
var you = {
name: 'Kim'
};
function sayName () {
console.log(this.name);
}
// 1
sayName.call(me); // output: JJ Yu
// 2
sayName.call(you); // output: Kim
var name = 'global name';
// 3
sayName(); // output: global name复制代码
上面代码我们主要关注一点就是执行上下文,在1、2的位置分别绑定me、you上下文对象,所以输出的是相对应的name值;在3位置前面定义了一个全局的name变量,并且在没有指定上下文环境被输出了,这也涉及到this的隐式绑定(在"this的绑定"讲会详细说明),绑定到了当前环境window。
下面我们把`sayName`函数显式的传递上下文对象:
// 声明一个传递上下文参数的函数
function sayName (context) {
console.log(context.name);
}
sayName(me); // output: JJ Yu
sayName(you); // output: Kim
复制代码
相比第一种(隐式绑定),显示传递上下文显得复杂,而且代码模式越复杂,这样传递上下文对象就会让代码越来越乱。
二、动态作用域和词法作用域
例1:
function increase (i) {
// this不是指向函数本身,而是指向了调用函数的上下文环境`window`
this.count++;
console.log(i);
}
increase.count = 0;
for(var i = 0; i < 5; i++) {
increase(i);
}
console.log(increase.count); // output: 0
// output:
// 0
// 1
// 2
// 3
// 4
// 0
复制代码
例2:
function increase (i) {
// 修改了,把指向指定到`increase`
increase.count++;
console.log(i);
}
increase.count = 0;
for(var i = 0; i < 5; i++) {
increase(i);
}
console.log(increase.count); // output: 5
// output:
// 0
// 1
// 2
// 3
// 4
// 5复制代码
例1中的this.count中的this并不是指向函数对象,而是在被调用时候指向了`window`;而例2使用`词法作用域`直接指定increase对象的count属性。
那为啥例1的this会被动态绑定到window对象呢?
// window
function increase (i) {
// this不是指向函数本身,而是指向了调用函数的上下文环境`window`
this.count++;
console.log(i);
}
increase(0); // 等价于 window.increase(0)
// 即是调用window下的方法,this指向window
复制代码
如果还有点不明白,来看下下面常见的场景:
var env = 'global';
function foo () {
this.env = 'foo function';
setTimeout(function () {
console.log(this.env); // ?
console.log(this === window); // true
})
}
foo();
复制代码
那么问号那行会输出:foo function;
总结:
- 函数中的this不是指向函数本身也不指向函数的词法作用域(见例1)
- this的绑定是发生在函数被调用时,至于this指向谁取决于函数在哪里被调用
三、this的绑定
在前面我们已经总结了this的指向,也就是绑定,是发生在函数被调用时。
调用位置:即函数在代码中被调用的位置(不是声明的位置),在这里只提及一下。
1、默认绑定(见例1)
这里需要注意的严格模式(strict mode)不能将全局对象用于默认绑定,此时this会绑定到undefined。
function foo () {
"strict mode";
console.log(this.env);
}
var env = 'global';
foo(); // TypeError: this is undefined复制代码
但在严格模式下调用函数不影响默认绑定:
function foo () {
"strict mode";
console.log(this.env);
}
var env = 'global';
(function () {
"strict mode";
foo(); // output: global
})();复制代码
2、隐式绑定
function foo () {
console.log(this.env);
}
var obj = {
env: 'obj',
foo: foo
}
obj.foo(); // output: obj复制代码
当foo()被调用时,它的前面加上了obj对象引用,调用位置会使用obj上下文来引用函数。
function foo () {
console.log(this.env);
}
var obj = {
env: 'obj',
foo: foo // => window -> obj
}
var f = obj.foo; // => obj -> window
var env = 'global';
f(); // output: global 复制代码
3、显示绑定
Function对象包含call以及apply两个方法,用来指定this的指向。详细用法自行百度。
var obj = {
name: 'JJ Yu'
}
var name = 'window';
function sayName () {
console.log(this.name);
}
sayName(); // output: window
sayName.call(obj); // output: JJ Yu
复制代码
硬绑定
var obj = {
name: 'JJ Yu'
}
function sayName () {
console.log(this.name);
}
function forceBind () {
sayName.call(obj);
}
setTimeout(forceBind);复制代码
es5提供了内置方法Function.prototype.bind:
var obj = {
name: 'JJ Yu'
}
function sayName () {
console.log(this.name);
}
setTimeout(sayName.bind(obj));复制代码
该方法返回一个硬编码(不知道是啥东东)的新函数,指定this的上下文以及调用原函数。
new绑定
var Person = function (name) {
this.name = name;
this.sayName = function () {
console.log(this.name);
}
}
var jj = new Person('JJ');
jj.sayName(); // output: JJ复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Practical Algorithms for Programmers
Andrew Binstock、John Rex / Addison-Wesley Professional / 1995-06-29 / USD 39.99
Most algorithm books today are either academic textbooks or rehashes of the same tired set of algorithms. Practical Algorithms for Programmers is the first book to give complete code implementations o......一起来看看 《Practical Algorithms for Programmers》 这本书的介绍吧!