javascript语法this总结

this一般分为根据作用域分为两种,一种是全局作用域下的this,另一种是函数作用域下的this。

一、全局作用域下的this

this运行只要是在函数外,this都是指向window的

二、函数作用域下的this

函数内部的this就比较复杂一点,因为存在多种情况,但是都有一个共同点,this取决于函数如何调用。也就是说,只有在函数被调用的时候,才存在this的指向。一般分为9种。

1、函数直接调用的情况

非严格模式下,直接调用函数,内部的this将指向window。

t = 10 //定义一个全局变量t
function test(){
  return this.t;
}
console.log(test()) // 10

严格模式下,直接调用函数,内部的this将指向该函数运行时的环境。

function test(){
  "user strict" //严格模式
  return this;
}
console.log(test()) //undefined

这个例子中,虽然函数是在window下面直接运行的,但是他没有被调用,而是直接运行,所以this是undefined。
我们稍微改一下上面的代码,你就知道了什么叫做运行环境。

function test(){
  "user strict" //严格模式
  return this;
}
console.log(window.test()) //window

使用了window来调用函数,那么,函数的执行环境就是window,所以函数内部的this === window。当然,这已经不属于函数直接调用的情况了。
再写一个自执行函数的例子。

(function test(){
  //"use strict"; 严格模式下this指向undefined
  var t = 9;
  console.log(this) // window
})()

无论是自执行还是直接调用函数,都是一样的,他没有“被调用”,所以就没有上下文环境。那么为什么非严格模式下面,会指向window呢,是不是说明非严格模式下默认指向window.test()?没错,但严格模式下就没有默认的说法了,严格模式下也没法给自执行函数指定window是不。

2、对象中的this。

当用对象调用自己里面定义的方法时,this指向的这个对象。
例如:

var obj = {
  id: 9,
  test: function() {
    return this.id;
  }
};
console.log(obj.test()); //9

这个例子中,test()是对象obj里面的方法,通过obj调用test方法obj.test(),那么该函数的运行环境就是obj所在的上下文,所以this指向obj。
有人可能就会想,直接运行test()呢?你要是能在对象之外直接运行test(),我就服了你。

接着就是匿名函数的调用,this又指向什么?

var obj = {id: 9};
function test() {
  return this.prop;
}
obj.t = test;
console.log(obj.t()); // logs 9

仍然输出obj的id9,这说明this始终与执行环境有关,这里的执行环境就是obj。

3、原型链中的this(属于对象例子的衍生)
看官方提供的一个有趣的例子。

var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5

首先定义一个对象o,对象里面有一个函数f,f里面有this,在对象o没有被调用的时候,f里面的this是没有意义的。
接着用create创建一个新的对象p继承了o的原型,那么p同时也就继承了o里面的函数f。
设置p.a = 1, p.b = 4,通过p.f()调用,则this的执行环境指向了对象p。
如果不创建原型,它是这样的。

var o = {
  f : function(){ 
    return this.a + this.b; 
  }
};
o.a = 1, o.b = 4
=>
var o = {
  a: 1,
  b: 4,
  f : function(){ 
    return this.a + this.b; 
  }
};
=>
o.f() // 5

4、getter与setter中的this(属于对象例子的衍生)
get和set可能很多人没有用过,get用来获取对象的属性,set用来设置对象的属性。

var obj = {
  a: 1,
  b: 2,
  get test(){
    return this.a + this.b;
  },
  set f(x) {
    this.a = x;
    this.b = x + 1;
  }
};
console.log(obj.test) //3
obj.f = 5
console.log(obj.test) //11

在上面的例子中,定义一个对象obj,有一个get,用来获取this.a + this.b的和,同理,单独一个对象中this是没有意义的,当obj调用它自身的test方法时obj.test,this就指向obj,因为obj是test的运行环境。
然后设置obj.f = 5,通过set设置obj的属性a和b的值为5和6,不再是1和2,之后再次调用obj.test,this仍旧指向obj。所以,无论你怎么调用对象内部函数中的this,它都是指向当前这个obj,因为obj是它的运行环境,上一个例子中的继承也是一个道理,只不过是通过继承对象的属性,使得运行环境在另外一个对象中。

5、构造函数中的this
如果你懂java或者C++,那么你一定知道“实例”这个概念,在JavaScript中,创建了一个构造函数,当我们使用new来实例化的时候,这个实例化的的对象就是一个运行环境,构造函数中的this就是指向实例化的对象。

function Templete(){
  this.a = 8;
}
var t = new Templete();
console.log(t.a); // 8

上面的例子中,有一个构造函数Templete,当new了一个新的对象t,那么this就指向了t,所以this.a == 8。

6、call和apply中的this
call和apply你如果熟悉的话,就会知道它的第一个参数是绑定函数的运行环境。

function add(x) {
  return this.a + x
}
var obj = {
  a: 10
}
var sum = add.call(obj, 8)
//var sum = add.apply(obj, [8])
console.log(sum) // 18

上面的例子中,我们定义了一个函数add,用来求a+x的和,但是这个a是用this.a指代的,我们如果直接运行add(x),无法给a设置值,这个时候就得apply和call登场了。
我们首先需要知道this.a从哪里来,这里定义了一个对象obj,设置了一个属性a,我们通过apply和call把add函数里面的this绑定到了obj对象中。
所以add里面的this指向的是obj对象。

7、bind中的this
bind中的this和apply和call是一样的,它的第一个参数用来绑定this指向的对象,记住是一个对象。

function f(x){
  return this.a + x;
}
var obj = {
  a: 10
}
var sum = f.bind(obj, 8);
console.log(sum()) // 18

还是第6种情况中的例子,只不过用bind来绑定当前函数的this指向obj,这里就不需要再重复解释一遍了。

8、DOM事件函数中的this
想必这个大家都比较了解了,我们监听一个DOM元素,给这个DOM元素绑定一个事件,那么事件函数中的this指向当前的DOM元素

var ele = document.getElementById('tab');
ele.addEventListener('click', func, false);
function func(e) {
    console.log(this === e.target) //true
}

这个例子中,给id叫做tab的元素绑定了click事件,事件名称叫做func,那么使得func()函数执行的环境是ele,所以func()函数中的this是指向ele元素。

9、内联事件中的this。
我们如果直接在dom元素上绑定一个事件,事件函数中的this直接指向的是它对应的dom元素,和第8种情况类似。

<div onclick="alert(this.tagName.toLowerCase())"></div>

打印出来是当前的div元素。

官方还举了一个特殊的例子,看下面。

<button onclick="alert((function(){return this})());">
  Show inner this
</button>

在这个特殊的例子中,alert里面是一个自执行函数,还记得我在第1种情况说的话吗?自执行函数没有被调用,所以严格模式下this是指向undefined的,而非严格模式下是指向window。

总结:这么多this的场景,其实它就一句话:this永远指向它执行的上下文环境。
无论是apply还是call还是bind,都只是为了给this指定一个上下文环境。

说了这么多ES5的this,记住,是浏览器端的,别拿服务端的this来说话。
关于ES6中的this,其实ES5中的构造函数和ES6中的class继承this的指向是一样的道理,其他的也一样,就不重复说了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值