在JS开发中,经常使用this,我觉得有必要对this进行总结一下。
定义
this 代表当前正在执行某个方法的对象,如果没有当前方法(或该方法不属于任何其它对象),则是指全局对象。也就是说,this代表调用该方法对象的引用。
全局范围中的this
全局里面的this,比较好理解,一般不容易出错。首先,看看下面代码,会输出什么呢?
<script type="text/javascript"> console.log(this==window); console.log(this);</script>1234
直接结果如下:
这说明,如果没有当前方法(或该方法不属于任何其它对象),则this是指全局对象window。
于是可以得出,输出一个 全局变量 ,可以采取下面几种方式
var name="dqs"; console.log(name); console.log(window['name']); console.log(window.name); console.log(this['name']); console.log(this.name);1234567
函数里面的this
函数里面的this,取决于函数的调用方式,调用方式不一样,那么里面的this也就会不一样。
直接以函数形式调用
直接以函数形式调用,函数里的this,代表全局对象,即window。
<script type="text/javascript">function fn(){ console.log(this); } fn();</script>123456
结果如下:
以全局对象的方法形式调用
以全局对象的方法形式调用,此时this,也代表全局对象,即window。
<script type="text/javascript">function fn(){ console.log(this); } fn(); console.log(this.fn()); console.log(window.fn());</script>12345678
借助call或者apply 函数调用
借助call或者apply函数调用时候,此时this代表指定的对象。
<script type="text/javascript">var obj={name:'obj_dqs'}; function fn(){ console.log(this); } function fn2(){ this.name='fn_dqs'; } fn.call(obj)//此时this代表obj fn.call(fn2)//此时this代表fn2</script>123456789101112
结果如下:
以 构造函数 形式调用
当以构造函数形式调用时候,此时this,代表创建的对象。
<script type="text/javascript">
var name='window_dqs'; function fn(){
this.name='fn_dqs'; this.showName=function(){
console.log(this.name);
}
console.log(this);
} var p=new fn();</script>1234567891011
结果如下图:
with中的this
在分析with(obj)中的this时候,我们需要分析其所在范围。如果是在函数中的this,代表obj,如果是全局范围变量中,则代表window
<script type="text/javascript"> var name='window_dqs'; var obj={ name:'obj_dqs', showName:function(){ console.log(this); }}; function showName(){ console.log(this); } with(obj){ console.log(this); showName(); } showName();</script>1234567891011121314151617181920
输出结果如下
以上是关于javascript中this的总结,然而实际上的操作中我们会遇到非常多的问题,让我们无从下手,在这里我给大家介绍一个自己的qun,里面有很多热情的大神,更有实际操作过的老手和老师,我也会不时分享学习的资料和视频(2131 26486),填写并私聊我(落叶)直接领取。
接下来看看我们在使用JavaScript的this的时候应当知道的。内容比较多,这里列举了一类,其他几类后面会再讲,都是用几年经验总结出来的,值得学习。
global this
在浏览器里,在全局范围内,this等价于window对象。
1 <script type="text/javascript"> 2 console.log(this === window); //true3 </script>
在浏览器里,在全局范围内,用 var 声明一个变量和给this或者window添加属性是等价的。
1 <script type="text/javascript"> 2 var foo = "bar"; 3 console.log(this.foo); //logs "bar" 4 console.log(window.foo); //logs "bar"5 </script>
如果你在声明一个变量的时候没有使用var或者let(ECMAScript 6),你就是在给全局的this添加或者改变属性值。
<script type="text/javascript"> foo = "bar"; function testThis() { foo = "foo"; } console.log(this.foo); //logs "bar" testThis(); console.log(this.foo); //logs "foo"11 </script>
在node环境里,如果使用REPL(Read-Eval-Print Loop,简称REPL:读取-求值-输出,是一个简单的,交互式的编程环境)来执行程序,this并不是最高级的命名空间,最高级的是global.
> this{ ArrayBuffer: [Function: ArrayBuffer], Int8Array:{ [Function: Int8Array] BYTES_PER_ELEMENT: 1 }, Uint8Array: { [Function: Uint8Array] BYTES_PER_ELEMENT: 1 }, ... > global === thistrue
在node环境里,如果执行一个js脚本,在全局范围内,this以一个空对象开始作为最高级的命名空间,这个时候,它和global不是等价的。
test.js脚本内容: console.log(this); console.log(this === global); REPL运行脚本: $ node test.js {} false
在node环境里,在全局范围内,如果你用REPL执行一个脚本文件,用var声明一个变量并不会和在浏览器里面一样将这个变量添加给this。
1 test.js: 2 3 var foo = "bar"; 4 console.log(this.foo); 5 6 $ node test.js 7 undefined
但是如果你不是用REPL执行脚本文件,而是直接执行代码,结果和在浏览器里面是一样的(神坑)
1 > var foo = "bar"; 2 > this.foo3 bar 4 > global.foo5 bar
在node环境里,用REPL运行脚本文件的时候,如果在声明变量的时候没有使用var或者let,这个变量会自动添加到global对象,但是不会自动添加给this对象。如果是直接执行代码,则会同时添加给global和this
1 test.js 2 3 foo = "bar"; 4 console.log(this.foo); 5 console.log(global.foo); 6 7 $ node test.js 8 undefined 9 bar
上面的八种情况可能大家已经绕晕了,总结起来就是:在 浏览器 里面this是老大,它等价于window对象,如果你声明一些全局变量(不管在任何地方),这些变量都会作为this的属性。在node里面,有 两种 执行JavaScript代码的方式,一种是直接执行写好的 JavaScript文件 ,另外一种是直接在里面执行 一行行代码 。对于直接运行一行行JavaScript代码的方式,global才是老大,this和它是等价的。在这种情况下,和浏览器比较相似,也就是声明一些全局变量会自动添加给老大global,顺带也会添加给this。但是在node里面直接脚本文件就不一样了,你声明的全局变量不会自动添加到this,但是会添加到global对象。所以相同点是,在全局范围内,全局变量终究是属于老大的。