基础知识时间长了也会忘, 虽然可能用对了, 但是又不知道为什么会对? 最后陷入了自我怀疑, this
可以说是js里面的灵魂关键字, 如果不能完全掌握它的原理, 你就不能随心所欲的使用.
DOM中使用this
来, 让我们以一个例子开始:
function doSomething() {
this.style.color = '#cc0000';
}
这里的this
指向谁? 在Javascript中 this
总是指向这个函数执行时的所以者. 如果用一句话来总结this的用法, 应该就是这一句. 如果 doSomething()直接在页面中调用 ,那它的所有者就是这个页面本身, 或者window对象(或者global对象).
如果是在html元素的onclick
属性中调用, 那this就指向这个HTML元素
element.onclick = doSomething;
有一个情况要特别注意:
<element onclick="doSomething()">
内联事件中的函数, 不是作为html元素的属性调用的! 它只是对函数的引用! 所以这里调用doSomethind()函数里面的this指向window, 因为它仅仅是找到doSomething然后执行它:
doSomething();
以下几种this指向html元素:
element.onclick = doSomething
element.addEventListener('click',doSomething,false)
element.onclick = function () {this.style.color = '#cc0000';}
<element onclick="this.style.color = '#cc0000';">
以下几种this指向window
element.onclick = function () {doSomething()}
<element onclick="doSomething()">
内联事件中正确用法:
<element onclick="doSomething(this)">
function doSomething(obj) {
// this is present in the event handler and is sent to the function
// obj now refers to the HTML element, so we can do
obj.style.color = '#cc0000';
}
全局环境
全局环境中(任何函数外) this
指向全局对象.
在浏览器中指向 window
函数内部环境
this
取决于函数调用的方式 (先不讨论严格模式))
看下面的例子
function f1(){
return this;
}
调用f1(), 将返回window对象, 因为直接调用f1()
相当于调用window.f1()
,所以这里的 this
指向window对象
如果想要改变this
的执行环境,就要用到call
or apply
方法.
看下面的例子
var obj = { a: 'chestnut'}
var a = 'pinapple'
function hold_what(arg){
return this.a;
}
hold_what(); // return 'pinapple'
hold_what.call(obj); // return 'chestnut'
hold_what.apply(obj); // return 'chestnut'
注意的是call或者apply的第一个参数,如果不是一个对象,js会尝试将其转换成对象.
bind方法调用this
调用f.bind(obj)
会创建一个新的函数, 但是函数体内的this
将永久的被绑定到obj. 无论这个函数在哪里被调用
function f(){
return this.a;
}
var g = f.bind({a:"azerty"});
console.log(g()); // azerty
var h = g.bind({a:'yoo'}); // bind只生效一次!
console.log(h()); // azerty
var o = {a:37, f:f, g:g, h:h};
console.log(o.f(), o.g(), o.h()); // 37, azerty, azerty
箭头函数内调用this
// 创建一个含有bar方法的obj对象,
// bar返回一个函数,
// 这个函数返回this,
// 这个返回的函数是以箭头函数创建的,
// 所以它的this被永久绑定到了它外层函数的this。
// bar的值可以在调用中设置,这反过来又设置了返回函数的值。
var obj = {
bar: function() {
var x = (() => this);
return x;
}
};
//作为对比,创建一个obj2
var obj2 = {
bar: function() {
var x = function(){ return this };
return x;
}
}
var fn = obj.bar();
var fn2 = obj2.bar();
console.log(fn()===obj); //结果1: 返回true
console.log(fn2()===obj2); //结果2: 返回false
console.log(fn2()===window); //结果3: 返回true
// 但是注意,如果你只是引用obj的方法,
// 而没有调用它
var fn3 = obj.bar;
// 那么调用箭头函数后,this指向window,因为它从 bar 继承了this。
console.log(fn3()() == window); // true
看结果,体会箭头函数和普通函数的区别. 特别注意这行注释 所以它的this被永久绑定到了它外层函数的this。
作为对象的方法调用this
函数作为对象里的方法调用时, this
指向调用该函数的对象.
var o = {
prop: 37,
f: function() {
return this.prop;
}
};
console.log(o.f()); // logs 37
看下面的例子
var o = {prop: 37};
function independent() {
return this.prop;
}
o.f = independent;
console.log(o.f()); // logs 37
o.b = {g: independent};
console.log(o.b.g()); // undefined
这里注意 o.b
的例子中,this指向o.b
.与她的对象o
没什么关系.
原型链中的this
var o = {
f: function() {
return this.a + this.b;
}
};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
如果该方法存在于一个对象的原型链上,那么this指向的是调用这个方法的对象,就像该方法在对象上一样。原型链这里很有意思. 虽然p没有f方法, 但是在它的原型链中找到了, 但是f是作为p的方法调用的, 所以它的this指向p. 多读两遍这句话, 真的很有意思.
构造函数中的this
当一个函数用作构造函数时(使用new关键字),它的this被绑定到正在构造的新对象。
如果构造函数中手动返回了对象, 那this绑定的默认对象就会被丢弃.
function C2(){
this.a = 37;
return {a:38};
}
o = new C2();
console.log(o.a); // logs 38
总结一下
JavaScript是面向对象的/