解读Javascript中的this机制,别再为了 this 发愁了

时间: 2017-11-10阅读: 643标签: this

题记:JavaScript中有很多令人困惑的地方,或者叫做机制。但是,就是这些东西让JavaScript显得那么美好而与众不同。比方说函数也是对象、闭包、原型链继承等等,而这其中就包括颇让人费解的this机制。不管是新手还是老手,不仔细深抠一下还真闹不明白this倒地咋回事捏。今天,我们就一起看一下this倒地咋回事,别再为了this发愁了。


1、this是啥?


简言之,this是JavaScript语言中定义的众多关键字之一,它的特殊在于它自动定义于每一个函数域内,但是this倒地指引啥东西却让很多人张二摸不着头脑。这里我们留个小悬念,希望看完这篇文章了你能回答出来this到底指引个甚。


2、this有啥用?


那边观众又该问了,既然this这么难以理解,那么为个甚还要用它呢?我们来看个例子:

function identify() {
    return this.name.toUpperCase();
}
function sayHello() {
    var greeting = "Hello, I'm " + identify.call( this );
    console.log( greeting );
}
var person1= {
    name: "Kyle"
};
var person2= {
    name: "Reader"
};
identify.call( person1); // KYLE
identify.call( person2); // READER
sayHello.call( person1); // Hello, I'm KYLE
sayHello.call( person2); // Hello, I'm READER


这段代码很简单,我们定义了两个函数,分别为identify和sayHello。并且在不同的对象环境下执行了它们,达到了复用的效果,而不用为了在不同的对象环境下执行而必须针对不同的对象环境写对应的函数了。简言之,this给函数带来了复用。那边客官又问了,我不用this一样可以实现,如:

function identify(context) {
    return context.name.toUpperCase();
}
function sayHello(context) {
    var greeting = "Hello, I'm " + identify( context);
    console.log( greeting );
}
var person1= {
    name: "Kyle"
};
var person2= {
    name: "Reader"
};
identify( person1); // KYLE
identify( person2); // READER
sayHello( person1); // Hello, I'm KYLE
sayHello( person2); // Hello, I'm READER


仔细一看,这位客官给出的解决方法的确也达到了类似的效果。赞一个!我想说的是,随着代码的增加,函数嵌套、各级调用等变得越来越复杂,那么传递一个对象的引用将变得越来越不明智,它会把你的代码弄得非常乱,甚至你自己都无法理解清楚。而this机制提供了一个更加优雅而灵便的方案,传递一个隐式的对象引用让代码变得更加简洁和复用。好了,知道了this的用处,那么再看看我们对它的误解。


3、关于this的误解


相信很多童鞋是学过其它语言的,在很多编程语言中都有this的机制,惯性思维把其它语言里对它的理解带到了JavaScript中。同时,由于this这个单词的理解导致了我们产生了对它各种各样的误解。所以,开始前,我们先澄清下对它的误解。


3.1 误解一:this引用function本身


我们都知道,在函数里引用函数可以达到递归和给函数属性赋值的效果。而这在很多应用场景下显得非常有用。所以,很多人都误以为this就是指引function本身。例如:

function fn(num) {
    console.log( "fn: " + num );
    // count用于记录fn的被调用次数
    this.count++;
}
fn.count = 0;
var i;
for (i=0; i<10; i++) {
    if (i > 5) {
        fn( i );
    }
}
// fn: 6
// fn: 7
// fn: 8
// fn: 9
console.log( fn.count ); // 0 -- 耶?咋不是4捏?


上面我们想要记录fn被调用的次数,可是明显fn被调用了四次但count仍然为0。咋回事捏?这里简单解释下,fn里第4行的自增隐式的创建了一个全局变量count,由于初始值为undefined,所以每一次自增其实依然不是一个数字,你在全局环境下打印count(window.count)输出的应该是NaN。而第6行定义的函数熟悉变量count依然没变,还是0。如果对这个执行结果不清楚的,欢迎去看我前些天的那篇博文(聊一下JS中的作用域scope和闭包closure scope和closure),在这里你只需要知道,this引用的是function这种理解是错误的就行。


这边就会又有人问了,既然this不是引用function,那么我要实现递归函数,该咋引用呢?这里简单回答下介个问题,两种方法:①函数体内用函数名来引用函数本身②函数体内使用arguments.callee来引用函数(不推荐)。那么既然第二种方法不推荐,匿名函数咋引用呢?用第一种,并且给匿名函数一个函数名即可(推荐)。


3.2 误解二:this引用的是function的词法作用域


这种误解欺骗的人可能更多一些。首先,澄清一下,this并没有引用function的词法作用域。的确JS的引擎内对词法作用域的实现的确像是一个对象,拥有属性和函数,但是这仅仅是JS引擎的一种实现,对代码来说是不可见的,也就是说词法作用域“对象”在JS代码中取不到。(关于词法作用域,如果不理解,可以参考之前的一篇博文《聊一下JS中的作用域scope和闭包closure scope和closure》)。看个错误的例子:

function fn1() {
    var a = 2;
    this.fn2();//以为this引用的是fn1的词法作用域
}
function fn2() {
    console.log( this.a );
}
fn1(); //ReferenceError


上面的代码明显没有执行出想要的结果,从而可以看到this并没有引用函数的词法作用域。甚至,可以肯定的说,这个例子里fn2可以在fn1里正确执行都是偶然的(理解了词法作用域你就知道为什么这里执行不报错了)。


4、this到底跟啥有关?


好了,扯了那么多都没上干货,有的观众都开始关闭当前页开始离席了。这里,我们郑重声明:this跟函数在哪里定义没有半毛钱关系,函数在哪里调用才决定了this到底引用的是啥。也就是说this跟函数的定义没关系,跟函数的执行有大大的关系。所以,记住,“函数在哪里调用才决定了this到底引用的是啥”。


5、this机制的四种规则


this到底绑定或者引用的是哪个对象环境决定于函数被调用的地方。而函数的调用有不同的方式,在不同的方式中调用决定this引用的是哪个对象是由四种规则确定的。我们一个个来看。


5.1 默认绑定全局变量


这条规则是最常见的,也是默认的。当函数被单独定义和调用的时候,应用的规则就是绑定全局变量。如下:

function fn() {
    console.log( this.a );
}
var a = 2;
fn(); // 2 -- fn单独调用,this引用window


5.2 隐式绑定


隐式调用的意思是,函数调用时拥有一个上下文对象,就好像这个函数是属于该对象的一样。例如:

function fn() {
    console.log( this.a );
}
var obj = {
    a: 2,
    fn: fn
};
obj.fn(); // 2 -- this引用obj。


需要说明的一点是,最后一个调用该函数的对象是传到函数的上下文对象(绕懵了)。如:

function fn() {
    console.log( this.a );
}
var obj2 = {
    a: 42,
    fn: fn
};
var obj1 = {
    a: 2,
    obj2: obj2
};
obj1.obj2.fn(); // 42 -- this引用的是obj2.


还有一点要说明的是,失去隐式绑定的情况,如下:

function fn() {
    console.log( this.a );
}
var obj = {
    a: 2,
    fn: fn
};
var bar = obj.fn; // 函数引用传递
var a = "全局"; // 定义全局变量
bar(); // "全局"


如上,第8行虽然有隐式绑定,但是它执行的效果明显是把fn赋给bar。这样bar执行的时候,依然是默认绑定全局变量,所以输出结果如上。


5.3 显示绑定


学过bind()\apply()\call()函数的都应该知道,它接收的第一个参数即是上下文对象并将其赋给this。看下面的例子:

function fn() {
    console.log( this.a );
}
var obj = {
    a: 2
};
fn.call( obj ); // 2


如果我们传递第一个值为简单值,那么后台会自动转换为对应的封装对象。如果传递为null,那么结果就是在绑定默认全局变量,如:

function fn() {
     console.log( this.a );
}
var obj = {
     a: 2
};
var a = 10;
fn.call( null); // 10


5.4 new新对象绑定


如果是一个构造函数,那么用new来调用,那么绑定的将是新创建的对象。如:

function fn(a) {
    this.a = a;
}
var bar = new fn( 2 );
console.log( bar.a );// 2


注意,一般构造函数名首字母大写,这里没有大写的原因是想提醒读者,构造函数也是一般的函数而已。


6、结束语


读到现在,1中问的问题你该自己能回答上来了。上面介绍的四种关于this绑定的4中情况和规则,现实写代码的过程中肯定比这要多和复杂,但是无论多复杂多乱,它们都是混合应用上面的几个规则和情况而已。只要你的思路和理解是清晰的,那肯定没问题的。


作者:front-Thinking  
来源:www.cnblogs.com/front-Thinking/p/4364337.htm


吐血推荐

1.阿里云: 本站目前使用的是阿里云主机,安全/可靠/稳定。点击领取2000元代金券、了解最新阿里云产品的各种优惠活动点击进入...

2.腾讯云: 提供云服务器、云数据库、云存储、视频与CDN、域名等服务。腾讯云各类产品的最新活动,优惠券领取点击进入...

3.站长广告联盟: 整理了目前主流的广告联盟平台,如果你有流量,可以作为参考选择适合你的平台点击进入...

链接: http://www.fly63.com/article/detial/79

理解 JS 中的 This, Bind, Call, 和 Apply

尽管这this是一个复杂的话题,但它也是在您开始编写第一个JavaScript程序后立即出现的话题。在本文中,您将了解什么this是指隐含根据上下文,您将学习如何使用bind,call和apply方法,明确确定的值this。

更细的角度来看 JS 中的 this

JS 中的this关键字对于初学者来说是一个谜,对于经验丰富的开发人员来说则是一个永恒的难题。this 实际上是一个移动的目标,在代码执行过程中可能会发生变化,而没有任何明显的原因。首先,看一下this关键字在其他编程语言中是什么样子的。

听说你很懂this,是真的吗?

his关键字是JavaScript中最复杂的机制之一,是一个特别的关键字,被自动定义在所有函数的作用域中,但是相信很多JvaScript开发者并不是非常清楚它究竟指向的是什么。听说你很懂this,是真的吗?

理解JavaScript函数调用和this

我看到很多人都有关于JavaScript函数调用的困惑。特别是,很多人抱怨函数调用中的语义令人困惑。在我看来,通过理解核心函数调用原语,可以清除很多这种混淆,然后查看在该原语之上调用函数作为语法糖的所有其他方法。

理解call apply bind以及其中所谓的改变this指向问题

上述代码很简单,小明有一只铅笔,有一把转笔刀,可以用来削铅笔,当我们调用;很明显会得到:小明使用了转笔刀把铅笔变成了削好的铅笔和木屑

JS中几种轻松处理this指向方式

与对象分离的方法会产生 this 指向不正确问题。静态地绑定this,可以手动使用一个附加变量self来保存正确的上下文对象。然而,更好的替代方法是使用箭头函数,其本质上是为了在词法上绑定this。在类中

解决这两种this混乱的场景,让它的指向明明白白!

this永远指向当前函数的主人,在构造函数中this指向新创建的对象,说明构造函数的主人是新创建的对象。但是有以下两种场景会引起this指向的混乱:

浅析js中的this

this是一个对象,一般存在于函数中,表示当前函数的执行上下文;值得一提的是,当函数在执行后,this才有绑定的对象,函数未执行时,this没有内容,接下来我们看看在不同场景下的this的指向

小程序中为什么使用var that=this?

在小程序或者js开发中,this是指当前对象,只是一个指针,真正的对象存放在堆内存中,this的指向在程序执行过程中会变化,因此如果需要在函数中使用全局数据需要合适地将this复制到变量中。

JS 中 this 在各个场景下的指向

很多时候, JS 中的 this 对于咱们的初学者很容易产生困惑不解。 this 的功能很强大,但需要一定付出才能慢慢理解它。对Java、PHP或其他标准语言来看,this 表示类方法中当前对象的实例

fly63.com版权所有,内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权,请与小编联系!情况属实本人将予以删除!

广告赞助文章投稿关于web前端网站点搜索站长推荐网站地图站长QQ:522607023

小程序专栏: 土味情话心理测试脑筋急转弯幽默笑话段子句子语录成语大全