javascript this关键字

this总是返回一个对象,即返回属性或方法当前所在的对象。

对象的属性可以赋给另一个对象,所以属性所在的当前对象是可变的,即this的指向是可变的。

eg:

var A = {
	name : '张三',
	describe : function(){
		return '姓名:' + this.name;
	}
};
var B = {
	name : '李四'
}
B.describe = A.describe;
B.describe();

结果:“姓名:李四”

再看一个例子:

var A = {
	name : '张三',
	describe : function(){
		return '姓名:' + this.name;
	}
};
var name = '李四'
f = A.describe;
f();

结果也是“姓名:李四”,因为这时this指向f运行时所在的对象——顶层window

this的使用场合

1、全局环境——无论this是不是在函数内部,只要是在全局环境下运行,this就是指顶层对象window

2、构造函数——指的是实例对象

eg:

var Obj = function(p){
	this.p = p;
}
Obj.prototype.a = function(){
	return this.p;
}
var obj = new Obj('color');
obj.a();
obj.p;

结果是都返回"color"

上面代码定义了一个构造函数Obj,由于this指向实例对象,所以在Obj中定义this.p,相当于定义实例对象有一个p属性,然后m方法可以返回这个p属性。

3、对象的方法

var obj = {
	foo : function(){
		console.log(this);
	}
};
obj.foo();//obj

只有直接在obj对象上调用foo方法,this才会指向obj,其他用法时,this都指向代码块当前所在的对象。

情况一:(obj.foo = obj.foo)()——window

情况二:(false || obj.foo)()——window

情况三:(1 , obj.foo)()——window

上述代码中,obj.foo先运算再执行,即使它的值没有变化,this也不再指向obj了

4、Node

在Node中,若在全局环境里,this指向global,模块环境中,this指向module.exports

this使用注意点

1、避免多层this

var o = {
	f1 : function(){
		console.log(this);
		var f2 = function(){
			console.log(this);
		}();
	}
}
o.f1();

执行结果是:

{f1: ƒ}

Window {decodeURIComponent: ƒ, postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, …}

为什么f2中的this指向的是全局对象呢?因为上面那段代码的执行过程实际上是

var temp = function(){
	console.log(this);
};
var o = {
	f1 : function(){
		console.log(this);
		var f2 = temp();
	}
}
o.f1();

解决方法一——在第二层改用一个指向外层this的变量

var o = {
	f1 : function(){
		console.log(this);
		var that = this;
		var f2 = function(){
			console.log(that);
		}();
	}
}
o.f1();

使用一个变量固定this的值,然后内层调用这个变量,是非常有用而且大量应用的方法

解决方法二——使用严格模式,在严格模式下,如果函数内部的this指向顶层对象就会报错。

2、避免数组处理方法中使用this

var o = {
	v : 'hello',
	p : ['a1','a2'],
	f : function(){
		this.p.forEach(function(item){
			console.log(this.v + ' ' + item);
		});
	}
}
o.f();

结果:

undefined a1

undefined a2

导致这个结果的原因跟上一段的多层this是一样的

解决方法一——使用中间变量

var o = {
	v : 'hello',
	p : ['a1','a2'],
	f : function(){
		var that = this;
		this.p.forEach(function(item){
			console.log(that.v + ' ' + item);
		});
	}
}
o.f();

解决方法二——将this当作forEach方法的第二个参数,固定它的运行环境

var o = {
	v : 'hello',
	p : ['a1','a2'],
	f : function(){
		this.p.forEach(function(item){
			console.log(this.v + ' ' + item);
		},this);
	}
}
o.f();

3、避免回调函数中的this

var o = new Object();
o.f = function(){
	console.log(this === o);
}
o.f();//true
$("#button").on("click",o.f);//false

绑定this的方法

JavaScript提供了call、apply、bind三个方法来切换/固定this的指向

function.prototype.call()

函数实例的call方法可以指定函数执行时this所在的作用域,call方法的参数量个对象,如果参数为空、null、undefined,则默认传入全局对象。如果call的参数不是对象,那么会被自动包装成包装对象。func.call(thisValue,arg1,arg2,……)

var n = 123;
var obj = {n : 456};
function a(){
	console.log(this.n);
}

a.call();//123
a.call(null);//123
a.call(undefined);//123
a.call(window);//123
a.call(obj);//456

call方法的一个应用是调用对象的原生方法

var obj = {};
//原生方法
obj.hasOwnProperty('toString');//false
//覆盖了原生的方法
obj.hasOwnProperty = function(){
	return true;
}
obj.hasOwnProperty('toString');//true
//调回原生的方法
Object.prototype.hasOwnProperty.call(obj,'toString');//false

function.prototype.apply()

apply与call唯一的区别是apply接受一个数组作为函数执行时的参数,func.apply(thisValue,[arg1,arg2,……])

apply的应用之一——找出数组的最大元素

var a = [10,3,4,2];
Math.max.apply(null,a);

apply的应用之二——将数组的空元素变为undefined(因为数组的forEach方法会跳过空元素,却不会跳过undefined)

var a = ['a','','b'];
function print(i){
	console.log(i);
}
a.forEach(print);//a b
Array.apply(null,a).forEach(print);//a undefined b

运行结果跟上面不太一样,都是a b

apply的应用之三——转换类似数组的对象

Array.prototype.slice.apply({0:1,length:1});

apply的应用之四——绑定回调函数的对象

var o = new Object();
o.f = function(){
	console.log(this === o);
}
var f = function(){
	o.f.apply(o);//或o.f.call(o);
}
$("#button").on("click",f);

function.prototype.bind()

bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数

下面的例子在将方法赋值后会出错

var d = new Date();
d.getTime();
var print = d.getTime;
print();//Uncaught TypeError: this is not a Date object.

解决方法:

var print = d.getTime.bind(d);

bind比call和apply更进一步的是,除了绑定this以外,还可以绑定原函数的参数

var add = function(x,y){
	return x * this.m + y * this.n;
}
var obj = {
	m:2,
	n:2
}
var newAdd = add.bind(obj,5);//绑定add的第一个参数x
newAdd(5);//第二个参数y

对于那些不支持bind方法的老式浏览器,可以自行定义bind方法

if(!('bind' in Function.prototype)){
	Function.prototype.bind = function(){
		var fn = this;
		var context = arguments[0];
		var args = Array.prototype.slice.call(arguments,1);
		return function(){
			return fn.apply(context,args);
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值