定义
简单的说
this
就是属性或方法运行时,当前
所在的对象。和运行时所处的环境相关,而与编写代码时所在位置无关(ES5)。
- 常规操作(1)
//最常见的用法var A = { name: '张三', describe: function () { return '姓名:'+ this.name; }};复制代码
this
属于方法describe
,而方法describe
又属于对A
,所以this
是指向的对象A
,在这个时候this.name
等同于a.name
- 常规操作(2)
function f() { return '姓名:'+ this.name;}var A = { name: '张三', describe: f};var B = { name: '李四', describe: f};var C = { name: '赵六', describe: function{ return '姓名:'+ this.name; }};var name='王五'var f2=C.describeA.describe() // "姓名:张三"B.describe() // "姓名:李四"f() // "姓名:王五"f2() //"姓名: 赵六"复制代码
由于
this
指向是根据环境变化的,所以A.describe()方法B.describe()输出的结果会不同,因为f方法的所在的对象变了。所以this指向改变了(注意: nodejs和浏览器环境下,this所指向的全局对象不一样,所以输出结果会不同。nodejs中f() 输出的为undefined,话说这个坑困扰了我很久!!
)
常见的坑
由于
this
只针对的指向不明确,所以会经常有各种坑。下面来列举一下几个常见的:
- 函数自执行的时候,
this
指向的事全局对象Window。先看一个复杂点的例子:
var o = { f1: function () { console.log(this); var f2 = function () { console.log(this); }(); }}o.f1()// Object (f1中输出的事对象o)// Window (f2中输出的是全局对象Window)复制代码
上述情况中
this
的指向,与我们想要的结果明显不符,上述代码实际执行的为:
var temp = function () { console.log(this);};var o = { f1: function () { console.log(this); var f2 = temp(); }}复制代码
函数自执行的定义:函数名+()的调用方式叫做自执行。 上面的temp()就是函数名加括号的调用方式,所以是自执行。
var f2 = function () { console.log(this); }(); //上述代码实际上可以转换为: var f2 = function () { console.log(this); }; f2(); //自执行复制代码
那么问题来了,为什么上述的o.f1()的时候,f1中的
this
指向的是对象o而不是全局对象window呢?答案在于方法和函数的区别,o.f1()表示的是调用的对象o中的方法,而f2()则表示的是调用函数f2(),它们最大的区别,就是有没有通过对象来调用。
知道区别了,接下来看看其他例子:
function fn(){ console.log(this); //Window } fn(); //最常见的自执行,函数加括号。以前只知道是指向全局,现在知道为什么了 复制代码
ES6箭头函数中的this
箭头函数是ES6中新增的一种简洁的函数书写方式,基本语法是:
参数 => 函数体
。 之所以把箭头函数单独拿出来说,是因为箭头函数与我们常见的函数,有很多不同之处,this
的指向就是区别之一。
箭头函数
this
的定义:箭头函数的中没有this
,所以箭头函数中的this
是直接继承(或者说调用)父级的this
,并且箭头函数的this
是在定义时绑定,所以和运行环境无关,这点和普通函数相反。
- 箭头函数
this
的例子:
var x = 11; var obj = { x: 22, say: () => { console.log(this.x); }, say2: function () { console.log(this.x); } } obj.say(); //输出11 obj.say2(); //输出22 //1.因为继承的是父级的this,而父级的this指向的是全局,所以say()拿到的数据是11//2.第二个普通方法,所以拿到的是x=22复制代码
setTimeout的this
先举个常见的栗子:
var Person = { 'age': 18, 'sayHello': function () { setTimeout(function () { console.log(this.age); }); }};var age = 20;Person.sayHello(); // 20var Person1 = { 'age': 18, 'sayHello': function () { setTimeout(()=>{ console.log(this.age); }); }};var age = 20;Person1.sayHello(); // 18复制代码
Person1.sayHello();
还比较好理解,因为使用了箭头函数,所以this
继承自sayHello
对象中this
,而sayHello
对象的this
指向的是Person1对象。所以Person1.sayHello()
中的this.age
实际上是Person1.age。那么为什么
Person.sayHello()
中console.log(this.age)
输出的是20
呢? 答案是由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的。