关于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复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。