关于this的那些事
栏目: JavaScript · 发布时间: 5年前
内容简介: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复制代码
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
史蒂夫·乔布斯传
[美] 沃尔特·艾萨克森 / 管延圻、魏群、余倩、赵萌萌、汤崧 / 中信出版社 / 2011-10-24 / 68.00元
这本乔布斯唯一授权的官方传记,在2011年上半年由美国出版商西蒙舒斯特对外发布出版消息以来,备受全球媒体和业界瞩目,这本书的全球出版日期最终确定为2011年11月21日,简体中文版也将同步上市。 两年多的时间,与乔布斯40多次的面对面倾谈,以及与乔布斯一百多个家庭成员、 朋友、竞争对手、同事的不受限的采访,造就了这本独家传记。 尽管乔布斯给予本书的采访和创作全面的配合,但他对内容从不干......一起来看看 《史蒂夫·乔布斯传》 这本书的介绍吧!