JavaScript 中的 this:
this指向是在运行函数时确定的,而不是定义函数时候确定的
匿名函数的执行环境具有全局性,因此其this 对象通常指向window(在通过call()或apply()改变函数执行环境的情况下,this 就会指向其他对象)
全局上下文:无论是否在严格模式下,在全局执行上下文中(在任何函数体外)this都指代全局对象
如:
1、console.log(this === window); // true
2、var girl={name:"amy",testThis:this}; console.log(girl.testThis); // window
(可理解为:var girl=new Object(); girl.name="amy"; girl.testThis=this;(指向window)
函数上下文:在函数内部,this的取值取决于函数被调用的方式
1、简单调用:
function f1(){
return this;
}
f1() === window; //在浏览器中,全局对象是window
非严格模式下,且this的值不是由该调用设置时(具体说就是不由该调用通过 call、apply、bind 这些方法来设置),this的值默认指向全局对象 严格模式下,this将保持它进入执行上下文时的值 所以默认为undefined
2、如果要想把 this 的值从一个上下文传到另一个,就要用 call 或者apply 方法
3、bind方法:
ECMAScript 5 引入了 Function.prototype.bind。调用f.bind(someObject)会创建一个与f具有相同函数体和作用域的函数,但是在这个新函数中,this将永久地被绑定到了bind的第一个参数,无论这个函数是如何被调用的
4、箭头函数:this与封闭词法上下文的this保持一致(即this被设置为它创建时的上下文)。如果将this的值传给call、bind、apply,它将被忽略,不过仍然可以为为调用添加参数,不过第一个参数应设置为null
5、作为对象的方法:当作为对象的方法被调用时,它们的this是调用该函数的对象,并且此时this的绑定只受最靠近的成员引用的影响
6、原型链中的this:this指向的是调用该方法的对象,就像该方法在对象上一样
7、getter(与setter)中的this:用作getter(或setter)的函数会把this绑定到获取(或设置)属性的对象上
8、作为构造函数:this被绑定到正在构造的新对象(虽然构造器返回的默认值是this所指的那个对象,但它仍可以手动返回其他的对象)
9、作为一个DOM事件处理函数:this指向触发事件的元素
10、作为一个内联事件处理函数:this指向监听器所在的DOM元素
如:
1、<button onclick="alert(this.tagName.toLowerCase());"> Show this </button> this指向button(注意只有外层代码中的this是这样设置的)
2、<button onclick="alert((function(){return this})());"> Show inner this </button> 这种情况下,没有设置内部函数的this,相当于函数简单调用的情况,所以它指向global/window对象
部分代码示例:
1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset="UTF-8"> 5 <title>This</title> 6 </head> 7 <body> 8 9 <script> 10 //全局上下文:无论是否在严格模式下,在全局执行上下文中(在任何函数体外)this都指代全局对象 11 var girl={ 12 name:"amy", 13 testThis:this 14 }; 15 /* 16 可理解为: 17 var girl=new Ojbect(); 18 girl.name="amy"; 19 girl.testThis=this; 20 */ 21 console.log(girl.testThis);//window 22 </script> 23 24 <script> 25 console.log("JS 是基于词法作用域的语言,函数在定义它的作用域中执行,而不是在调用它的作用域中执行"); 26 console.log("类的方法默认是不会绑定 this 的,作为对象的方法:当作为对象的方法被调用时,它们的this是调用该函数的对象,并且this的绑定只受最靠近的成员引用的影响"); 27 console.log("-----------About Amy --------------"); 28 var Amy={ 29 name:"Amy", 30 sex:"girl", 31 amyOutter:function(){ 32 console.log("amyOutter:",this); 33 return function(){ 34 console.log("amyAnonymous:",this); 35 }; 36 } 37 }; 38 console.log("----Amy.func amyOutter -----"); 39 var amy_anony=Amy.amyOutter(); 40 //输出: amyOutter: {name: "Amy", sex: "girl", amyOutter: ƒ} 41 // 解析:作为对象的方法调用 42 43 console.log("----Amy.func amyOutter quote-----"); 44 var quote=Amy.amyOutter;//获取Amy.amyOutter函数的引用 45 quote(); 46 //输出:amyOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 47 // 解析:这里相当于简单调用 48 49 console.log("----Amy.func amyAnonymous-----"); 50 amy_anony(); 51 //输出: amyAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 52 // 解析:直接调用返回的匿名函数 53 54 amy_anony.call(Amy); 55 //输出: amyAnonymous: {name: "Amy", sex: "girl", amyOutter: ƒ} 56 // 解析:Amy用call调用返回的匿名函数 57 58 </script> 59 60 <script> 61 console.log("-----------About Mike -----------"); 62 var Mike={ 63 name:"Mike", 64 sex:"boy", 65 mikeOutter:function(){ 66 console.log("mikeOutter:",this); 67 (function(){ 68 console.log("mikeAnonymous:",this); 69 })(); 70 } 71 }; 72 73 console.log("----Mike.func mikeOutter---"); 74 Mike.mikeOutter(); 75 //输出: mikeOutter: {name: "Mike", sex: "boy", mikeOutter: ƒ} 76 // 解析:作为对象的方法调用 77 //输出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 78 // 输出:window 解析:匿名函数被调用 79 80 console.log("----Mike.func mikeOutter quote-----"); 81 var quote=Mike.mikeOutter;//获取Mike.mikeOutter函数的引用 82 quote(); 83 //输出:mikeOutter: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 84 // 解析:这里相当于简单调用 85 //输出: mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 86 // 解析:匿名函数被调用 87 88 console.log("---Mike func call---"); 89 Mike.mikeOutter.call(Amy); 90 //输出: mikeOutter: {name: "Amy", sex: "girl", amyOutter: ƒ} 91 // 解析:Amy 用call调用返回的匿名函数 92 //输出:mikeAnonymous: Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …} 93 // 解析:匿名函数被调用 94 95 </script> 96 97 <script> 98 console.log("-----------About Guang -----------"); 99 var Guang={ 100 name:"Guang", 101 sex:"boy", 102 GuangOutterOne:function(){ 103 console.log("GuangOutterOne:",this); 104 var that=this; 105 // 正确 that 中保留了对 this 的引用 106 this.GuangOutterTwo(function(){ 107 that.GuangOutterThree(); 108 }); 109 110 // 正确 匿名函数直接绑定 this 111 // this.GuangOutterTwo(function(){ 112 // this.GuangOutterThree(); 113 // }.bind(this)); 114 115 // 出错 匿名函数作参数 this 为 window ,window 无 GuangOutterThree 方法 116 // this.GuangOutterTwo(function(){ 117 // this.GuangOutterThree(); 118 // }); 119 }, 120 GuangOutterTwo:function(cb){ 121 console.log("GuangOutterTwo:",this); 122 cb(); 123 }, 124 GuangOutterThree:function(){ 125 console.log("GuangOutterThree:",this); 126 } 127 }; 128 129 console.log("----Guang.func GuangOutterOne---"); 130 Guang.GuangOutterOne(); 131 //输出:GuangOutterOne: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ} 132 //解析:作为对象的方法调用 133 134 //输出: GuangOutterTwo: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ} 135 //解析: GuangOutterOne 中的 this 指向 Guang 调用 Guang 中的 GuangOutterTwo 方法 136 137 //输出: GuangOutterThree: {name: "Guang", sex: "boy", GuangOutterOne: ƒ, GuangOutterTwo: ƒ, GuangOutterThree: ƒ} 138 //解析: that 保留对 this 的引用 调用 Guang 中的 GuangOutterTwo 方法 139 140 141 </script> 142 143 <script> 144 console.log("JS 是基于词法作用域的语言,函数在定义它的作用域中执行,而不是在调用它的作用域中执行"); 145 console.log("箭头函数:this与封闭词法上下文的this保持一致(即this 被设置为他被创建时的上下文)"); 146 var foo=(()=>this); 147 /* 148 可以把箭头函数看成是 149 var foo=function(){ 150 //other code 151 return this; 152 //此处this所在的函数被创建时是在全局环境中 因为 this被设置为他被创建时的上下文 所以 this就被设置为window 153 }; 154 */ 155 // 由下可见 无论如何,foo 中的 this 都被设置为他被创建时的上下文(在上面的例子中,就是全局对象) 156 // 注意:对于箭头函数 如果将this传递给call、bind、或者apply,它将被忽略 不过你仍然可以为调用添加参数,不过第一个参数(thisArg)应该设置为null 157 var obj = {foo: foo}; 158 console.log("直接调用:",foo()===window,", call调用:",obj.foo() === window,", apply调用:",foo.call(obj) === window,", bind绑定:",foo.bind(obj)() === window); // true true true true 159 160 //这同样适用于在其他函数内创建的箭头函数:这些箭头函数的this被设置为封闭的词法上下文的 161 console.log("-----------About John ------------------"); 162 var John={ 163 name:"John", 164 johnOutter:function(){ 165 //console.log("johnOutter",this);//johnOutter中的this具体情况可参考上面的Amy和Mike实例 166 var x=(()=>this); 167 //此处this所在的函数被创建时是在johnOutter中 因为 this被设置为他被创建时的上下文 所以 this就被设置为 johnOutter 函数中的this 168 return x; 169 } 170 } 171 172 var fn=John.johnOutter();//获取返回的函数 若去掉johnOutter中console.log语句的注释 输出:John 解析:解析:作为对象的方法调用 173 console.log("John.johnOutter():",fn()); 174 //输出:John.johnOutter(): Object { name: "John", johnOutter: johnOutter() } 175 //解析:此时johnOutter函数由John调用 所以johnOutter函数中的this为John,而箭头函数的this被设置为johnOutter的this 176 177 var quote=John.johnOutter;//获取John.johnOutter函数的引用 178 console.log("quote:",quote()()); 179 //输出:window 180 //解析:此时quote获取johnOutter的引用,quote()相当于简单调用,所以johnOutter函数中的this为window,而箭头函数的this被设置为johnOutter的this 181 182 /** 183 * 对于箭头函数: 184 * 1、确定箭头函数是在哪个执行环境中被创建的 185 * 2、根据执行环境确定this被设置为哪个执行环境 186 * 3、最后对函数的调用参考对象中的方法调用即可 187 * 总结可以简单理解为: 188 * 箭头函数的this在全局执行上下文创建时 它的this就是全局上下文中的this 189 * 箭头函数的this在非全局执行上下文创建时,它的this就与封闭词法上下文中的this保持一致
190 */ 191 192 </script> 193 194 </body> 195 </html>