js 函数 this
其实关于js中的this到底是个什么东西,我看了N多资料都没搞清楚。反正不是全局作用域就是某个对象,那就用笨方法,把所有用到this的情况都写一遍,看看能不能从中找到什么规律吧。
本文使用非严格模式测试、浏览器环境(360、谷歌)
各种我能想到的例子
function aaa(){
alert(this === window);
}
aaa(); //true
this指向全局作用域
由于aaa()
可以算是window.aaa()
的简写,那会不会是与这个window有什么直接关系呢?于是写了下面的例子
function b(){
function bb(){
alert(this === window); //true
}
bb();
}
window.b();
应该也不是这种关系,因为在b函数内无法使用window.b.bb();
这样的语句。
那么看起来就是,用function xxx(){}
这样的方式定义的函数的方法体内,this指的就是window(全局变量)。真的是这样么?
function f1(){
alert(this === a); //true
}
function f2(){
function ff2(){
alert(this === window); //true
}
ff2();
}
var a = {
aaa: f1,
bbb: f2
};
a.aaa();
a.bbb();
坑爹的事情发生了,它们都返回true。也就是说,this指代的对象,一个是a,一个是window
这时再回过头来想一下看过无数遍的那句话:***this的值取决于调用方式***
-
f1中this的指向问题看来是解决了。a是window中的一个对象,所以通过a调用时,this被绑定成了a
-
对于ff2中的this,就有些奇怪了。无论用什么样的方式调用,都指向的window。于是可以这样认为:对于这种直接定义的函数(function xxx(){}),当采用xxx()的形式调用时,内部的this就是指向window的。(我对这样的结论非常不满意,这实在是有些不严谨,但是又找不到反例,就先这么认为吧)
看来this确实是取决于调用方式的。再写几个例子来加深印象吧。
//匿名函数返回对象的方式调用
function f1(){
console.log(this);
}
var aaa = function(){
return {
f1: f1
}
}();
aaa.f1(); //指向aaa
f1(); //指向window
不需要解释。
//多重嵌套下的调用
function f1(){
console.log(this === bbb); //true
}
var bbb = {
b1: f1
};
var aaa = {
a1: bbb
}
aaa.a1.b1();
f1是由a1直接调用的,a1就是bbb。可以得出,this指向的是最近的、直接调用的对象。这很符合直观印象。
//在上述基础上改一下,将值赋予一个全局变量后再调用
function f1(){
console.log(this === window); //true
}
var bbb = {
b1: f1
};
var aaa = {
a1: bbb
}
var ccc = aaa.a1.b1;
ccc();
这是作为全局变量(ccc)来调用的,所以this指的也是window。
//通过new创建的函数
var a = function(){
var that = this;
this.f1 = function(obj){
console.log(this === obj); //true
console.log(that === obj); //true
}
};
var b = new a();
b.f1(b);
可以的出this指代的是实例化对象。
。。。。。。
同样的一段代码通过不同的方式调用竟然可以出现不同的结果,这真是一大败笔。
既然它这么坑,那官方肯定也是提供了一套解决方案的,那就是显式的指定this。
call apply
语法
call(thisObj, parameter1, parameter2 …)
apply(thisObj, [parameter1, parameter2 …])
这两个方法都是有函数本身调用,不同的是call需要将参数一个一个传入,apply则是将参数列表作为一个数组传入。
用call来改写一下上面的语句
var a = function(){
var that = this;
this.f1 = function(obj){
console.log(this === window); //true
console.log(that === obj); //true
}
};
var b = new a();
b.f1.call(window, b);
可以看得出,call将f1的this显式的指定为了window。不过,a中的this依然指的是a的实例化对象,这也正是我们想要的结果。
收集来的一些练习题
基本都涉及一些this之外的知识点
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
return function(){
return this.name;
};
}
};
alert(object.getNameFunc()());
var name = "The Window";
var object = {
name : "My Object",
getNameFunc : function(){
var that = this;
return function(){
return that.name;
};
}
};
alert(object.getNameFunc()());
//https://www.zhihu.com/question/21172721/answer/17413362
var age = 3;
var cat1 = new function() {
this.name = 'Tom';
this.age = 2;
this.weight = function(age) {
var age = age * 2;
var _age = this.age * 2;
return 'weight by age:' + age + '; weight by this.age:' + _age;
}(this.age);
this.eye = new function() {
this.size = '1.5cm';
this.color = 'red';
};
this.catching = function(mouse) {
return this.name + ' is catching ' + mouse;
};
};
alert(cat1.weight);
alert(cat1.eye.color);
alert(cat1.catching('Jerry'));
//https://www.cnblogs.com/pizitai/p/6427433.html
var personA={
name:"xl",
showName:function(){
console.log(this.name);
}
}
var personB={
name:"XL",
sayName:personA.showName
}
personB.sayName();
var myObject = {
foo: "fff",
func: function() {
var self = this;
console.log("outer func : this.foo = " + this.foo);
console.log("outer func : self.foo = " + self.foo);
(function() {
console.log("inner func : this.foo = " + this.foo);
console.log("inner func : self.foo = " + self.foo);
}());
}
}
myObject.func();
//看来内部的匿名自执行函数的this也是指代的全局对象
var length = 10;
function fn() {
console.log(this.length);
}
var obj = {
length: 5,
method: function(fn) {
fn();
arguments[0]();
console.log(arguments);
}
};
obj.method(fn, 1);
//每当你觉得自己会了的时候,总会有这样的一道题来击碎你的幻想......
//https://blog.csdn.net/sinat_36521655/article/details/80253311
有时间再收集一些。
网上收集的例子很多都不严谨,如果本文有什么错误,欢迎指正。
上一篇: js基础(一)