JavaScript中有很多令人困惑的地方,或者叫做机制。但是,就是这些东西让JavaScript显得那么美好而与众不同。比方说函数也是对 象、闭包、原型链继承等等,而这其中就包括颇让人费解的this机制。不管是新手还是老手,不仔细深抠一下还真闹不明白this倒地咋回事捏。今天,我们 就一起看一下this倒地咋回事,别再为了this发愁了。
this是啥?
简言之,this是JavaScript语言中定义的众多关键字之一,它的特殊在于它自动定义于每一个函数域内,但是this倒地指引啥东西却让很多人张二摸不着头脑。希望看完这篇文章了你能回答出来this到底指引个甚。
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的误解
相信很多童鞋是学过其它语言的,在很多编程语言中都有this的机制,惯性思维把其它语言里对它的理解带到了JavaScript中。同时,由于this这个单词的理解导致了我们产生了对它各种各样的误解。所以,开始前,我们先澄清下对它的误解。
误解一: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来引用函数(不推荐)。那么既然第二种方法不推荐,匿名函数咋引用呢?用第一种,并且 给匿名函数一个函数名即可(推荐)。
误解二: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里正确执行都是偶然的(理解了词法作用域你就知道为什么这里执行不报错了)。
this到底跟啥有关?
好了,扯了那么多都没上干货,有的观众都开始关闭当前页开始离席了。这里,我们郑重声明:this跟函数在哪里定义没有半毛钱关系,函数在哪里调用才 决定了this到底引用的是啥。也就是说this跟函数的定义没关系,跟函数的执行有大大的关系。所以,记住,“函数在哪里调用才决定了this到底引用 的是啥”。
this机制的四种规则
this到底绑定或者引用的是哪个对象环境决定于函数被调用的地方。而函数的调用有不同的方式,在不同的方式中调用决定this引用的是哪个对象是由四种规则确定的。我们一个个来看。
默认绑定全局变量
这条规则是最常见的,也是默认的。当函数被单独定义和调用的时候,应用的规则就是绑定全局变量。如下:
- function fn() {
- console.log( this.a );
- }
- var a = 2;
- fn(); // 2 -- fn单独调用,this引用window
隐式绑定
隐式调用的意思是,函数调用时拥有一个上下文对象,就好像这个函数是属于该对象的一样。例如:
- 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执行的时候,依然是默认绑定全局变量,所以输出结果如上。
显示绑定
学过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
new新对象绑定
如果是一个构造函数,那么用new来调用,那么绑定的将是新创建的对象。如:
- function fn(a) {
- this.a = a;
- }
- var bar = new fn( 2 );
- console.log( bar.a );// 2
注意,一般构造函数名首字母大写,这里没有大写的原因是想提醒读者,构造函数也是一般的函数而已。
相关推荐
js中 JSON的使用全解.docx
js中 JSON的使用全解.pdf
2. **函数没有所属对象(全局环境)**:在非严格模式下,如果函数不在任何对象作用域内被调用,`this` 指向全局对象(在浏览器中是 `window`,在 Node.js 环境中是 `global`)。例如: ```javascript function foo...
js原生态函数中使用jQuery中的$(this)无效的解决方法 在JavaScript开发中,使用jQuery的$(this)在原生态函数中可能会出现无效的问题,本文将对此进行详细的分析和解决方法的介绍。 一、问题描述 在JavaScript开发...
在JavaScript编程语言中,`this`关键字是一个至关重要的概念,它常常引发初学者的困惑,因为它的值在不同的上下文中可能会有所不同。`this`关键字主要用来引用对象的上下文,或者说是当前执行环境中的对象。在本文中...
本书全方位地介绍了JavaScript开发中的各个主题,无论是前端还是后端的JavaScript开发者都可以在本书中找到自己需要的内容。本书对HTML5、Web API、Node.js及WebSocket等最新的热门技术也作了深入浅出的介绍,并提供...
3. javascript中onclick中的this:这是调用obj.value得到的结果,显示了触发事件的元素的value属性值。 总结来说,在javascript中,onclick(this)的用法主要是将当前被点击的元素作为上下文对象传递给事件处理函数...
### JavaScript基础语法全解 ...以上内容概述了《JavaScript基础语法全解》中关于变量和条件语句的基础知识。通过对这些概念的理解,初学者可以更好地掌握JavaScript的核心语法,为进一步学习打下坚实的基础。
JavaScript中的`this`关键字是程序设计中的一个核心概念,它在不同上下文环境中有着不同的指向,这使得理解和掌握`this`的用法至关重要。在JavaScript中,`this`的值取决于函数调用的方式,而不是定义的方式,这为...
JavaScript中this的指向还没搞明白?来这看看 你就懂啦~
### JavaScript 中 `this` 的用法详解 #### 一、引言 在 JavaScript 开发过程中,`this` 关键字的使用...掌握 `this` 的用法有助于开发者更好地理解 JavaScript 中的函数调用机制,进而编写出更加健壮和灵活的代码。
JavaScript中的this关键字是一个非常重要的概念,它在函数执行时确定了函数的执行上下文。在其他编程语言中,函数的调用上下文可能是明确的,但在JavaScript中,this的指向却可能因为多种不同的规则而变化,从而导致...
- **全局或函数外部**:在全局作用域中,`this`指向`window`对象(在浏览器环境中)或全局对象(在Node.js中)。 - **对象方法**:当函数作为对象的一个方法被调用时,`this`指向调用该方法的对象。 - **构造函数...
Vue.js 是一款非常流行的前端JavaScript框架,以其易学易用、高效灵活的特性深受开发者喜爱。本小册将深入解析Vue.js的内部运行机制,帮助读者从基础到核心原理进行全面理解,从而提升开发效率和代码质量。以下是...
JavaScript中的`this`关键字是一个非常重要的概念,它在不同上下文中具有不同的指向,这使得理解和掌握`this`的用法成为JavaScript开发中的关键点。在本文中,我们将深入探讨`this`在全局变量、函数、对象、构造函数...
复习JavaScript中this指向及绑定
Vue.js 是一款流行的前端框架,它的核心特性之一是数据绑定。在 Vue 中,我们通常使用 `data` 选项来声明初始数据。然而,在某些场景下,我们可能需要在运行时动态地添加或修改数据属性,这时就需要用到 `this.$set`...
在本话题中,我们将深入探讨JavaScript中的类继承,并特别关注`this.callParent`这个方法,它是如何被用来调用超类方法的。 首先,让我们了解JavaScript中的构造函数。构造函数是一种特殊的函数,用于创建和初始化...
浅谈javascript中this在事件中的应用.doc
JavaScript中的`this`关键字是一个非常重要的概念,它用于在函数执行时引用当前上下文的对象。`this`的值取决于函数被调用的方式,这通常分为四种情况:纯粹的函数调用、作为对象方法的调用、作为构造函数调用以及...