this指向问题
1、全局环境下
在全局环境下,this 始终指向全局对象(window), 无论是否严格模式;
1 this.a = 37; 2 window.a // 37
2. 函数上下文调用
1) 、函数直接调用
普通函数内部的this分两种情况,严格模式和非严格模式
非严格模式下,this指向全局对象window
1 function fn(){ 2 return this; 3 } 4 5 fn === window; // true
严格模式下,this为undefined
function foo(){ "use strict"; return this; } foo === undefined; // true
2)、对象中的this
对象内部方法的this指向调用这些方法的对象
1. 函数的定义位置不影其this的指向,this指向只和调用函数的对象有关。
2. 多层嵌套的对象,内部方法的this指向离被调用函数最近的对象(window也是对象,其内部对象调用方法的this指向内部对象,而非window)。
// 第一种 var o = { prop: 37, f: function() { console.log(this); return this.prop; } }; console.log(o.f()); //37 var a = o.f; // this 指向window console.log(a()); //undefined var o = {prop: 37}; function independent() { return this.prop; } o.f = independent; console.log(o.f()); // logs 37 // 第二种 o.b = { g: independent, prop: 42 }; console.log(o.b.g()); // logs 42
3)、原型链中this
原型链中的方法的this任然指向调用它的对象
可以看出, 在p中没有属性f,当执行p.f()时,会查找p的原型链,找到 f 函数并执行,但这与函数内部this指向对象 p 没有任何关系,只需记住谁调用指向谁。
以上对于函数作为getter & setter 调用时同样适用。
4)、构造函数中this
构造函数中this与被创建的新对象绑定。
注意:当构造器返回的默认值是一个this引用的对象时,可以手动设置返回其他的对象,如果返回值不是一个对象,返回this。
function C(){ this.a = 37; } var o = new C(); console.log(o.a); // logs 37 function C2(){ this.a = 37; return {a:38}; } var b = new C2(); console.log(b.a); // logs 38
5)、call & apply
当函数通过Function对象的原型中继承的方法call() 和apply() 方法调用时,其函数内部的this值可以绑定到call() & apply() 方法指定的第一个对象上, 如果第一个参数不是对象,Jacascript内部会尝试将其转换成对象然后指向它。
function add(c, d){ return this.a + this.b + c + d; } var o = {a:1, b:3}; add.call(o, 5, 7); // 1 + 3 + 5 + 7 = 16 add.apply(o, [10, 20]); // 1 + 3 + 10 + 20 = 34 function tt() { console.log(this); } // 返回对象见下图(图1) tt.call(5); // Number {[[PrimitiveValue]]: 5} tt.call('asd'); // String {0: "a", 1: "s", 2: "d", length: 3, [[PrimitiveValue]]: "asd"}
6)、bind方法
bind方法在ES5引入, 在Function的原型链上,Function.prototype.bind。通过bind方法绑定后,函数将永远绑定在其第一个参数对象上,而无论在什么情况下被调用。
function f(){ return this.a; } var g = f.bind({a:"azerty"}); console.log(g()); // azerty var o = {a:37, f:f, g:g}; console.log(o.f(), o.g()); // 37, azerty
3、DOM事件处理函数中的this& 内联事件中的this
DOM 事件处理函数
1. 当函数被当作间挺事件处理函数时,其this,指向处罚该事件的元素(针对addEventListener事件)
// 被调用时,将关联的元素变成蓝色 function bluify(e){ //在控制台打印出所点击元素 console.log(this); //阻止时间冒泡 e.stopPropagation(); //阻止元素的默认事件 e.preventDefault(); this.style.backgroundColor = '#A5D9F3'; } // 获取文档中的所有元素的列表 var elements = document.getElementsByTagName('*'); // 将bluify作为元素的点击监听函数,当元素被点击时,就会变成蓝色 for(var i=0 ; i<elements.length ; i++){ elements[i].addEventListener('click', bluify, false); }
2.内联事件
内联事件中的this指向分两种情况
* 当代码被内联处理函数调用时,它的this指向监听所在的DOM元素
* 当代码被包括在函数内部执行时,其this指向等同于*****函数直接调用情况*****,即在非严格模式指向全局对象window,严格模式指向undefined
3、setTimeout & setInterval
对于延时函数内部的回调函数的this指向全局对象window(当然我们可以通过bind方法改变其内部函数的this指向)
//默认情况下代码 function Person() { this.age = 0; setTimeout(function() { console.log(this); // window }, 3000); } var p = new Person();//3秒后返回 window 对象 ============================================== //通过bind绑定 function Person() { this.age = 0; setTimeout((function() { console.log(this); // p 对象 }).bind(this), 3000); } var p = new Person();//3秒后返回构造函数新生成的对象 Person{...}
4、箭头函数中的this
由于箭头函数不绑定this,它会捕获其所在(即定义的位置)上下文的this的值,作为自己的this值
1)、所以call() / apply() / bind() 方法对于箭头函数来说只是传入参数,对它的this毫无影响。
2)、考虑到this时词法层面上的,严格模式中与this相关的规则都将被忽略。(可以忽略是否在严格模式下的影响)
var adder = { base : 1, add : function(a) { var f = v => v + this.base; return f(a); }, addThruCall: function inFun(a) { var f = v => v + this.base; var b = { base : 2 }; return f.call(b, a); } }; console.log(adder.add(1)); // 输出 2 console.log(adder.addThruCall(1)); // 仍然输出 2(而不是3,其内部的this并没有因为call() 而改变,其this值仍然为函数inFun的this值,指向对象adder
箭头函数this指向全局window对象,而普通函数则指向调用它的对象