JavaScript this探究

xiaoxiao2021-03-01  23

关于javascript的this讲解的文章已经多如牛毛了,我本人在开发过程中也用到过很多次。这次趁有空,整理一下关于this的一系列问题:包括this的指向,严格模式和非严格模式下的区别,什么情况下可以改变this的指向以及在ES6下箭头函数中this的指向。

一.严格模式下this的指向

严格模式下:

function aa(){ 'use strict'; console.log(this) //undefined } aa();

非严格模式下:

function aa(){ console.log(this) //window } aa();

二.this的指向

MDN中对this的解释如下:

在绝大多数情况下,函数的调用方式决定了this的值。this不能在执行期间被赋值,并且在每次函数被调用时this的值也可能会不同。

简单点来说,this的指向在声明时是未定义的,只有在它被调用时才会被赋值,要搞清楚它到底指向什么,只要搞清楚到底谁调用它即可。

下面有几种情况可以帮助我们加快理解this的指向问题:

1.第一种情况:

function aa(){ console.log(this) //window } aa();

此时是window对象调用了aa()函数,所以this指向window。

2.第二种情况

var test = { aa:"hello", bb:function(){ console.log(this.aa) //"hello" } } test.bb();

此时是test对象调用了this,所以this此时指向的bb对象中的aa;

var test = { aa:"hello", bb:function(){ console.log(this) //test (object) } } test.bb();

此时就很清晰的能看到this指向的test对象。

3.第三种情况

var test = { aa:"hello", bb:{ aa:'hello2', cc:function(){ console.log(this.aa) //"hello2" } } } test.bb.cc();

此时调用cc中this的对象是bb,而不是test,所以this指向的是bb。

以上三个例子已经比较清晰的解释了this的指向问题: 谁最后调用了this,谁就是this指向的对象。

三.什么情况下this的指向会被改变

这些情况大致可以分为两类:

1.关键字类。主要有new,return 2.函数类。 主要有call,apply,bind

第一类.关键字类 我们先看new的例子:

function aa(){ this.name = "Tom" } var bb = aa(); //bb is undefined; var bb = new aa(); console.log(bb.name) //"Tom"

new关键字的关键在于实例化了构造函数aa()。使它的函数能够顺利的拿到里面的name。

return的例子:

function aa(){ this.name = "Tom"; return {}; } var bb = new aa(); console.log(bb.name) //undefined

当return的内容是一个对象时,则this会指向这个对象。

function aa(){ this.name = "Tom"; return 'aaa'; } var bb = new aa(); console.log(bb.name) //"Tom"

当return的内容是一个非对象时,则this的指向不会发生改变。

第二类.函数类

1.call()函数 老规矩,先关门放MDN。

call() 方法调用一个函数,其具有一个指定的this值和分别地提供的参数(参数的列表)。

简单来说就是可以通过call()函数来指定你想调用的this所造的环境,同时还可以追加多个参数。 以下是MDN上的官方示例:

function Product(name, price) { this.name = name; this.price = price; } function Food(name, price) { Product.call(this, name, price); this.category = 'food'; } console.log(new Food('cheese', 5).name); // expected output: "cheese"

如果没有调用call()函数,最后打印的应该是food,调用后才会改成cheese。如果觉得上面的例子还不够清晰,我们可以再看一个,如果觉得ok了,请跳过。

var aa = { name:"tom", bb:function(x, y){ console.log(this.name); //"tom" console.log(x,y); // 1,2 } } var b = aa.bb b.call(aa); b.call(aa,1,2)

2.apply函数

apply() 方法调用一个具有给定this值的函数,以及作为一个数组(或类似数组对象)提供的参数。 该方法的作用和 apply()方法类似,只有一个区别,就是call()方法接受的是若干个参数的列表,而apply()方法接受的是一个包含多个参数的数组。

var aa = { name:"tom", bb:function(x, y){ console.log(this.name); //"tom" console.log(x,y); // 1,2 } } var b = aa.bb b.apply(aa,[1,2])

3.bind函数

bind()方法创建一个新的函数, 当这个新函数被调用时其this置为提供的值,其参数列表前几项置为创建时指定的参数序列。

var module = { x: 42, getX: function() { return this.x; } } var unboundGetX = module.getX; console.log(unboundGetX()); // The function gets invoked at the global scope // expected output: undefined var boundGetX = unboundGetX.bind(module); console.log(boundGetX()); // expected output: 42

需要注意的是,bind函数与apply和call都有所不同,不同之处在于bind不是立即执行的。

bind() 函数会创建一个新绑定函数,绑定函数与被调函数具有相同的函数体(在 ECMAScript 5 中)。

我们看一个例子:

var aa = { name:"tom", bb:function(){ console.log(this.name) } } var cc = aa.bb; var dd = cc.bind(aa); console.log(dd); //type function aa() dd(); // "tom"

三.ES6箭头函数中的this

箭头函数与其他函数区别很大,我们直接看MDN:

箭头函数表达式的语法比函数表达式更短,并且没有自己的this,arguments,super或 new.target。

function Person(){ this.age = 0; setInterval(() => { this.age++; // |this| 正确地指向person 对象 }, 1000); } var p = new Person();

当然,通过相关函数也不能改变=>中的this指向。

通过 call 或 apply 调用 由于 箭头函数没有自己的this指针,通过 call() 或 apply() 方法调用一个函数时,只能传递参数(不能绑定this—译者注),他们的第一个参数会被忽略。(这种现象对于bind方法同样成立—译者注)

总结一下,在箭头函数中,是没有它自己的this的,它只会从自己的作用域链的上一层继承this。 我们来看例子:

var obj = { fn:()=>{ console.log(this) //window } }; obj.fn();

再看一个:

function obj(){ let aa = ()=>{ console.log(this); } aa(); } obj() // window var bb = new obj(); //obj type object

第二个例子中,new obj()后之所以打印出了obj(),是因为new关键字绑定了this到返回的新的对象object中。

转载请注明原文地址: https://www.6miu.com/read-4150152.html

最新回复(0)