当前位置: 首页 > 编程日记 > 正文

彻底理解js中this

相关博文:http://blog.csdn.net/libin_1/article/details/49996815

彻底理解js中this的指向,不必硬背。


首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然网上大部分的文章都是这样说的,虽然在很多情况下那样去理解不会出什么问题,但是实际上那样理解是不准确的,所以在你理解this的时候会有种琢磨不透的感觉),那么接下来我会深入的探讨这个问题。

为什么要学习this?如果你学过函数式编程,面向对象编程,那你肯定知道干什么用的,如果你没有学过,那么暂时可以不用看这篇文章,当然如果你有兴趣也可以看看,毕竟这是js中必须要掌握的东西。

例子1:

function a(){var user = "追梦子";console.log(this.user); //undefinedconsole.log(this); //Window
}
a();

按照我们上面说的this最终指向的是调用它的对象,这里的函数a实际是被Window对象所点出来的,下面的代码就可以证明。

function a(){var user = "追梦子";console.log(this.user); //undefinedconsole.log(this);  //Window
}
window.a();

和上面代码一样吧,其实alert也是window的一个属性,也是window点出来的。

例子2:

复制代码
var o = {user:"追梦子",fn:function(){console.log(this.user);  //追梦子
    }
}
o.fn();
复制代码

这里的this指向的是对象o,因为你调用这个fn是通过o.fn()执行的,那自然指向就是对象o,这里再次强调一点,this的指向在函数创建的时候是决定不了的,在调用的时候才能决定,谁调用的就指向谁,一定要搞清楚这个。

其实例子1和例子2说的并不够准确,下面这个例子就可以推翻上面的理论。

如果要彻底的搞懂this必须看接下来的几个例子

本文出处:追梦子博客

例子3:

复制代码
var o = {user:"追梦子",fn:function(){console.log(this.user); //追梦子
    }
}
window.o.fn();
复制代码

这段代码和上面的那段代码几乎是一样的,但是这里的this为什么不是指向window,如果按照上面的理论,最终this指向的是调用它的对象,这里先说个而外话,window是js中的全局对象,我们创建的变量实际上是给window添加属性,所以这里可以用window点o对象。

这里先不解释为什么上面的那段代码this为什么没有指向window,我们再来看一段代码。

复制代码
var o = {a:10,b:{a:12,fn:function(){console.log(this.a); //12
        }}
}
o.b.fn();
复制代码

这里同样也是对象o点出来的,但是同样this并没有执行它,那你肯定会说我一开始说的那些不就都是错误的吗?其实也不是,只是一开始说的不准确,接下来我将补充一句话,我相信你就可以彻底的理解this的指向的问题。

情况1:如果一个函数中有this,但是它没有被上一级的对象所调用,那么this指向的就是window,这里需要说明的是在js的严格版中this指向的不是window,但是我们这里不探讨严格版的问题,你想了解可以自行上网查找。

情况2:如果一个函数中有this,这个函数有被上一级的对象所调用,那么this指向的就是上一级的对象。

情况3:如果一个函数中有this,这个函数中包含多个对象,尽管这个函数是被最外层的对象所调用,this指向的也只是它上一级的对象,例子3可以证明,如果不相信,那么接下来我们继续看几个例子。

复制代码
var o = {a:10,b:{// a:12,fn:function(){console.log(this.a); //undefined
        }}
}
o.b.fn();
复制代码

尽管对象b中没有属性a,这个this指向的也是对象b,因为this只会指向它的上一级对象,不管这个对象中有没有this要的东西。

还有一种比较特殊的情况,例子4:

复制代码
var o = {a:10,b:{a:12,fn:function(){console.log(this.a); //undefinedconsole.log(this); //window
        }}
}
var j = o.b.fn;
j();
复制代码

这里this指向的是window,是不是有些蒙了?其实是因为你没有理解一句话,这句话同样至关重要。

 this永远指向的是最后调用它的对象,也就是看它执行的时候是谁调用的,例子4中虽然函数fn是被对象b所引用,但是在将fn赋值给变量j的时候并没有执行所以最终指向的是window,这和例子3是不一样的,例子3是直接执行了fn。

  this讲来讲去其实就是那么一回事,只不过在不同的情况下指向的会有些不同,上面的总结每个地方都有些小错误,也不能说是错误,而是在不同环境下情况就会有不同,所以我也没有办法一次解释清楚,只能你慢慢地的去体会。

构造函数版this:

function Fn(){this.user = "追梦子";
}
var a = new Fn();
console.log(a.user); //追梦子

这里之所以对象a可以点出函数Fn里面的user是因为new关键字可以改变this的指向,将这个this指向对象a,为什么我说a是对象,因为用了new关键字就是创建一个对象实例,理解这句话可以想想我们的例子3,我们这里用变量a创建了一个Fn的实例(相当于复制了一份Fn到对象a里面),此时仅仅只是创建,并没有执行,而调用这个函数Fn的是对象a,那么this指向的自然是对象a,那么为什么对象Fn中会有user,因为你已经复制了一份Fn函数到对象a中,用了new关键字就等同于复制了一份。

除了上面的这些以外,我们还可以自行改变this的指向,关于自行改变this的指向请看JavaScript中call,apply,bind方法的总结这篇文章,详细的说明了我们如何手动更改this的指向。

更新一个小问题当this碰到return时

复制代码
function fn()  
{  this.user = '追梦子';  return {};  
}
var a = new fn;  
console.log(a.user); //undefined
复制代码

再看一个

复制代码
function fn()  
{  this.user = '追梦子';  return function(){};
}
var a = new fn;  
console.log(a.user); //undefined
复制代码

再来

复制代码
function fn()  
{  this.user = '追梦子';  return 1;
}
var a = new fn;  
console.log(a.user); //追梦子
复制代码
复制代码
function fn()  
{  this.user = '追梦子';  return undefined;
}
var a = new fn;  
console.log(a.user); //追梦子
复制代码

什么意思呢?

如果返回值是一个对象,那么this指向的就是那个返回的对象,如果返回值不是一个对象那么this还是指向函数的实例。

复制代码
function fn()  
{  this.user = '追梦子';  return undefined;
}
var a = new fn;  
console.log(a); //fn {user: "追梦子"}
复制代码

还有一点就是虽然null也是对象,但是在这里this还是指向那个函数的实例,因为null比较特殊。

复制代码
function fn()  
{  this.user = '追梦子';  return null;
}
var a = new fn;  
console.log(a.user); //追梦子
复制代码

知识点补充:

1.在严格版中的默认的this不再是window,而是undefined。

2.new操作符会改变函数this的指向问题,虽然我们上面讲解过了,但是并没有深入的讨论这个问题,网上也很少说,所以在这里有必要说一下。

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

为什么this会指向a?首先new关键字会创建一个空的对象,然后会自动调用一个函数apply方法,将this指向这个空对象,这样的话函数内部的this就会被这个空的对象替代。

相关文章:

cvsdfgdfdf

数组-136. 只出现一次的数字题目描述题目样例Java方法:位运算算法思路代码复杂度题目描述 给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。 题目样例 示例1: 输入: […

怎样操作vue.js使用3DES加密

如何在VUE-CLI手脚架建立的工程中使用3des加密: 1npm install crypto-js --save-dev1import CryptoJS from crypto-js123456789101112131415161718192021222324252627//DES加密 Pkcs7填充方式encryptByDES(message, key){const keyHex CryptoJS.enc.Utf8.parse(key…

PHP 函数 ignore_user_abort定时执行任务的实现

ignore_user_abort 设置与客户机断开是否会终止脚本的执行。本函数返回 user-abort 设置的之前的值(一个布尔值)。int ignore_user_abort ([ string $value ] )参数描述setting可选。如果设置为 true,则忽略与用户的断开,如果设置…

echarts树图节点垂直间距_矿棉板吊顶标准工艺节点

材料探秘materials材料版块【矿棉板吊顶标准工艺】 材料探秘关键词:#吊杆与设备#吊顶龙骨#矿棉板#1 吊杆与设备相遇增加过桥节点图 ■ 本工艺管控要点◎ 顶面的水、电、风专业强制定位、预留、预埋必须全部完成,且电气穿线、测试完成并合格&#xf…

队列 queue

STL: 队列中pop完成的不是取出最顶端的元素,而是取出最低端的元素.也就是说最初放入的元素能够最先被取出(这种行为被叫做FIFO:First In First Out,即先进先出). queue:front 是用来访问最底端数据的函数. 1 #include <queue>2 #include <cstdio>3 uisng namespace…

Android精通:View与ViewGroup,LinearLayout线性布局,RelativeLayout相对布局,ListView列表组件...

UI的描述 对于Android应用程序中&#xff0c;所有用户界面元素都是由View和ViewGroup对象构建的。View是绘制在屏幕上能与用户进行交互的一个对象。而对于ViewGroup来说&#xff0c;则是一个用于存放其他View和ViewGroup对象的布局容器&#xff01; Android为我们提供了View和V…

redis删除过期key的算法_面试官别再问我Redis内存满了该怎么办了

概述Redis的文章&#xff0c;我之前写过一篇关于「Redis的缓存的三大问题」&#xff0c;累计阅读也快800了&#xff0c;对于还只有3k左右的粉丝量&#xff0c;能够达到这个阅读量&#xff0c;已经是比较难了。这说明那篇文章写的还过得去&#xff0c;收到很多人的阅读肯定&…

开源监控解决方案Nagios+Cacti+PNP4Nagios+NConf+NDOUtils+Nagvis(六)ndoutils安装

前面的文章已经说过&#xff0c;NDOUtils必须使用2.0的版本才支持nagios4x&#xff0c;比较幸运的是该版本2014年就已经发布。一.安装#tar -axf ndoutils-2.0.0.tar.gz -C /usr/local/src/#cd /usr/local/src/ndoutils-2.0.0#./configure --prefix/usr/local/nagios LDFLAGS-L/…

网络安全技术分析:DDoS的攻与防

根据墨者安全相关数据研究发现&#xff0c;从今年年初开始&#xff0c;DDoS功击的数量相比去年几乎是翻倍增长&#xff0c;特别是游戏、金融、政企、电商、医疗行业&#xff0c;更是DDoS功击的重灾区&#xff0c;很多企业是闻“D”色变。DDos(Distributed Denial of Service),中…

pcl求平面法向量_线性代数6——平面方程与矩阵

线性方程的几何意义二元线性方程该方程是一个二元线性方程组&#xff0c;包含两个方程&#xff0c;每个方程是一条直线&#xff0c;两条直线的交点就是该方程有唯一解&#xff0c;这就是二元线性方程的几何意义。平面方程空间内不在同一直线上的三点构成一个平面&#xff0c;平…

php 类中的各种拦截器

1、__get( $property ) 访问未定义的属性时调用class lanjie {function __get($name){echo $name." property not found! ";} }$ob new lanjie(); echo $ob->g; 当我们调用对象$ob未定义的属性g时&#xff0c;调用拦截器__get()方法&#xff0c;输出“g property…

[Vue CLI 3] 源码之 webpack-chain

我们看一下 webpack-chain 到底做什么? Use a chaining API to generate and simplify the modification of Webpack version 2-4 configurations.熟悉 cli-plugin-babel、cli-plugin-eslint 源码的话&#xff0c;你会时常看到它。 如何使用呢&#xff1f; 1、加载它 const Co…

openstack页面自定义插件使用详解(django、ajax、post)(zTree为例)

2019独角兽企业重金招聘Python工程师标准>>> 感谢朋友支持本博客&#xff0c;欢迎共同探讨交流&#xff0c;由于能力和时间有限&#xff0c;错误之处在所难免&#xff0c;欢迎指正&#xff01; 如有转载&#xff0c;请保留源作者博客信息。 Better Me的博客&#xf…

lazyload.js实现图片异步延迟加载

所谓图片异步加载&#xff0c;意思是不用一次把图片全部加载完&#xff0c;你可以叫它延迟加载&#xff0c;缓冲加载都行。 看看你有没有这种需求&#xff1a;某篇文章图片很多&#xff0c;如果在载入文章时就载入所有图片&#xff0c;无疑会延缓载入速度&#xff0c;让用户等…

postfilter中文什么意思_Filterpost请求中文字符编码的过滤器 --学习笔记

java代码&#xff1a;import java.io.IOException;import java.io.PrintWriter;import javax.servlet.ServletException;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Lo…

错误:You can't specify target table 'xxx' for update in FROM clause的解决

今天在MySQL数据库删除重复数据的时候遇到了一个问题。如下脚本&#xff1a; DELETE FROM tempA WHERE tid IN ( SELECT MAX(tid) AS tid FROM tempA GROUP BY name,age ) 会出现报错信息&#xff1a; You cant specify target table tempA for update in FROM clause 大致意思…

HTTPS的七个神话(译文)

原文网址&#xff1a;http://blog.httpwatch.com/2011/01/28/top-7-myths-about-https/ 译文地址&#xff1a;http://www.ruanyifeng.com/blog/2011/02/seven_myths_about_https.html 误解七&#xff1a;HTTPS无法缓存 许多人以为&#xff0c;出于安全考虑&#xff0c;浏览器不…

蓝牙写入数据库_蓝牙 数据写入 简单易懂版(适合没写过蓝牙的看)

//字符串转arrbufferfunction string2buffer(str) {// 首先将字符串转为16进制let val ""for (let i 0; i < str.length; i) {if (val ) {val str.charCodeAt(i).toString(16)} else {val , str.charCodeAt(i).toString(16)}}// 将16进制转化为ArrayBufferr…

Educational Codeforces Round 9 F. Magic Matrix 最小生成树

F. Magic Matrix题目连接&#xff1a; http://www.codeforces.com/contest/632/problem/F Description Youre given a matrix A of size n  n. Lets call the matrix with nonnegative elements magic if it is symmetric (so aij  aji), aii  0 and aij ≤ max(aik, …

【SqlServer】SqlServer中的更新锁(UPDLOCK)

UPDLOCK.UPDLOCK 的优点是允许您读取数据&#xff08;不阻塞其它事务&#xff09;并在以后更新数据&#xff0c;同时确保自从上次读取数据后数据没有被更改。当我们用UPDLOCK来读取记录时可以对取到的记录加上更新锁&#xff0c;从而加上锁的记录在其它的线程中是不能更改的只能…

Oracle CDC (Change Data Capture)更新数据捕获——概述

Change Data Capture能高效识别并捕获数据的插入、修改和删除&#xff0c;使更新数据供个人或应用使用。 CDC从oracle 9i开始引入&#xff0c;//TODO 在11G R2之后的版本里将取消支持&#xff0c;被Oracle GoldenGate取代。 CDC的一些概念 CDC有同步和异步两种模式&#xff0c;…

flutter ios启动白屏_Flutter技术架构概览

前言最近在整理各种技术架构&#xff0c;给自己的列了个TODO list&#xff0c;希望能在几个月的时间内&#xff0c;研究完各种前端技术架构&#xff0c;包括移动端技术架构。今天分享一下自己整理的flutter技术架构。完整的技术架构TODO list可以去我的github仓库查看&#xff…

SQL Relay开源的数据库池连接代理服务器

一、SQL Relay是什么&#xff1f; SQL Relay是一个开源的数据库池连接代理服务器 二、SQL Relay支持哪些数据库&#xff1f;* Oracle* MySQL* mSQL* PostgreSQL* Sybase* MS SQL Server* IBM DB2* Interbase* Sybase* SQLite* Lago* ODBC* MS Access三、安装和配置&#xff1b;…

关于Android开源库分享平台,(GitClub)微信小程序的开发体验

七八月份的深圳一直在下雨&#xff0c;总有人说雨天适合窝在家看书&#xff0c;对于程序开发者来说更是难得的学习机会。我们502工作室的小伙伴利用这个时间学习了一下微信小程序开发&#xff0c;并上线了一个GitClub小程序&#xff0c;目前功能有些简陋&#xff0c;难免有辣眼…

RSync实现文件备份同步

rsync是类unix系统下的数据镜像备份工具&#xff0c;从软件的命名上就可以看出来了——remote sync。它的特性如下&#xff1a;1、可以镜像保存整个目录树和文件系统。2、可以很容易做到保持原来文件的权限、时间、软硬链接等等。3、无须特殊权限即可安装。4、优化的流程&#…

Hibernate annotation多对多配置

角色&#xff08;用户组&#xff09;&#xff0c;用户多对多。 角色实体配置&#xff1a; private Set<TAuthUser> users;ManyToManyJoinTable(name"t_auth_user_role",joinColumns{JoinColumn(name"role_id")},inverseJoinColumns{JoinColumn(name&…

ajax中的url如何传递变量_如何创建和参数化UDT数据类型中的变量及IN,OUT 等参数?...

从数据类型的意义上说 UDT 并不被 CPU 所识别&#xff0c;而是在离线程序中自定义(组合)的数据类型。 S7 程序的自定义数据类型并不能装载到 S7 CPU 中。UDT 是由递增的编辑器创建并编辑或由源文件的编译而生成。 当在块调用中进行变量传递时是不能将 UDT 作为内存地址区域来传…

[雪峰磁针石博客]kotlin书籍汇总

2019独角兽企业重金招聘Python工程师标准>>> 下载地址 Learning Kotlin by Building Android Applications - 2018 初级 Develop amazing applications that will help you understand and explore the fundamentals of Kotlin while covering 3 various types of p…

web集群时session同步的3种方法

web集群时session同步的3种方法在做了web集群后&#xff0c;你肯定会首先考虑session同步问题&#xff0c;因为通过负载均衡后&#xff0c;同一个IP访问同一个页面会被分配到不同的服务器上&#xff0c;如果session不同步的话&#xff0c;一个登录用户&#xff0c;一会是登录状…

属于python文件的操作有_Python的文件操作

1、初始文件操作1、使用python读写文件使用open()函数获取文件句柄&#xff0c;就可以操作文件了&#xff0c;根据打开方式不同能执行的操作也不同。打开方式有&#xff1a;r、w、a、r、w、a、rb、wb、ab、rb、wb、ab&#xff0c;默认用的是r模式2、只读操作(r、rb)2.1、只读模…