this对象的涵义就是指向当前对象中的属性和方法。(所以关键在于当前对象是什么)。this总是与调用位置有关,与声明位置无关。即谁调用这个函数或方法,this关键字就指向谁。
扩展:javascript是词法作用域 / 静态作用域(就是说这个标识符写在哪里,就只能在哪里用)。
以下我们通过一些例子来有关this关键字的一些用法。
-
浏览器中,当调用方法没有明确的指向时,默认指向window。
node中,顶级作用域module.exports,指向global;但在node-cli下与浏览器一致。
举个栗子:
var obj = {
name:'a',
foo:function(){
console.log(this.name)
}
}
var obj2 = {
name:'b',
foo:obj.foo
}
obj.foo(); //a
obj2.foo(); //b
var obj3 = {
name:'b',
foo:function(){
var testfoo = obj.foo;
testfoo();
}
}
obj3.foo(); //undifined,这时this指向window ,因为testfoo并没有一个明确的对象调用它
-
在浏览器中setTimeout,setInterval和匿名函数执行时的当前对象是window
// 栗子3
var name = 'b';
var obj = {
name:'c',
showname:function(){
console.log(this.name)
},
foo:function(){
(function(cb){
cb();
})(this.showname)//立即执行函数,此时this的指向是window
}
}
obj.foo();
-
eval 等同于在声明位置填入代码。所以该函数执行时的作用域是当前作用域。
// 栗子4 eval
var name = 'a';
var obj = {
name:'c',
showName:function(){
eval(console.log(this.name)); //其实等同于直接console.log(this.name)
}
}
obj.showName(); //c
-
apply,call
提到this关键字不得不提apply,call ,它们能强制改变函数执行时的对象,即可以改变this指向。
// 栗子5 apply
var name = 'b';
var obj = {
name:'c',
showname:function(){
console.log(this.name)
}
}
var obj2 = {
name:'d'
}
obj.showname.apply();
obj.showname.apply(null);
obj.showname.apply(undifined); //b,指向window
obj.showname.apply(obj2); //d
call与apply作用是一样的,也是改变this指向。不同之处在于传参形式。如下:
function test(a, b) {
console.log(a + b);
}
test.apply(null, [1, 2]); //3
test.call(null, 1, 2); //3
//第一个参数是指定函数内部中this的指向,这里指向全局
-
bind
提到call与apply,这里还需要提一下bind,它有个特性 柯里化(将多个参数的函数变成只带一个参数的函数)。
举个栗子:
var sum = function(x,y) {
return x + y
};
var succ = sum.bind(null, 1); //让this指向null,其后的实参也会作为实参传入被绑定的函数sum
succ(2) // => 3: 1已经绑定到了sum函数中的x
call和apply模拟实现bind
Function.prototype.bind = function(context) {
var _this = this, args = Array.prototype.slice.call(arguments);
return function() {
return _this.apply(context, args.slice(1));
}
};
-
es6箭头函数
因为javascript的this很古怪,所以从es6出现了箭头函数,它在声明时绑定this,通过babel转化。
var name = 'a';
var obj = {
name:'b',
showName:()=>{
console.log(this.name)
}
}
obj.showName(); //a ,this指向window