在 JavaScript 中,this 是指当前函数中正在执行的上下文环境;当你调用一个函数时,this总是作为一个(隐式)参数。
(1)、宽松模式下的普通函数:
this总是指向全局对象,(在浏览器中是window)
var a=123;
var A=function(){
return this; //Window
}
(2)、严格模式下
使用严格模式,只需要将 ‘use strict’ 置于函数体的顶部。this总是undefined;
var a=123;
var A=function(){
'use strict';
return this; //undefined
}
(3)方法
this指向调用方法的对象
var qwe={
method:function(){
return this;
}
}
console.log(qwe.method()===qwe) ; //true
在讲call()之前先说一下,函数调用有4中类型:
函数调用 alert('Hello World!')
方法调用 console.log('Hello World!')
构造函数调用 new RegExp('\\d')
间接调用 alert.call(undefined, 'Hello World')
注意:this 是指当前函数中正在执行的上下文环境
陷阱:this 在内部函数中
一个常见的陷阱是理所应当的认为函数调用中的,内部函数中 this 等同于它的外部函数中的 this。
正确的理解是内部函数的上下文环境取决于调用环境,而不是外部函数的上下文环境。
为了获取到所期望的 this,应该利用间接调用修改内部函数的上下文环境,如使用 .call() 或者 .apply或者创建一个绑定函数 .bind()。
利用call、apply、bind这三个方法,可以改变this的指向,使它指向我们期望的对象。
一、call()
关于javascript中的call方法,总结网上的观点,call有两个妙用:
1: 修改函数运行时的this指针。
2: 继承。(不太喜欢这种继承方式。)
简单说明一下
var f=function(){}
f.call(o)
解释:一个简单的例子,在全局环境下创建一个变量f,在函数f里面的this指向全局,window;但是利用call方法,将this指向了对象o,在o的作用域中运行函数f。
1、call()的完整使用格式:
func.call(thisValue, arg1, arg2, ...)
第一个参数是this要重新指向的那个对象,后面的参数是调用时所需要的参数;
或者是:
Function.prototype.call(thisValue, arg1, arg2, ...)
说明 :
call 方法可以用来代替另一个对象调用一个方法。
obj1.method1.call(obj2,argument1,argument2)
如上,call的作用就是把obj1的方法method1放到obj2上使用,后面的argument1..这些做为参数传入。
简单例子如下:
function one1(a,b){
console.log(a+b);
};
function two1(a,b){
console.log(a-b);
};
one1.call(two1,5,2); //7
这个例子中的意思就是用 one1来替换 two1,所以运行结果为:7
// 注意:js 中的函数其实是对象,函数名是对 Function 对象的引用。
看个稍微复杂的例子:
function duixiang1(){
this.name="zyy";
this.method=function(){
return this.name;
}
};
function duixiang2(){
this.name="zxd";
}
var q1=new duixiang1();
var q2=new duixiang2();
console.log(q1.method()); //zyy
console.log(q1.method.call(q2)); //zxd
解释:call 的意思是把 q1的方法放到q2上执行,原来q2是没有method() 方法,现在是把q1 的method()方法放到 q2 上来执行,所以this.name 应该是 zxd,执行的结果就是 :zxd;
有意思吧,可以让a对象来执行b对象的方法。还有更有趣的,可以用 call 来实现继承 :
接下来说明一下call()实现继承:
function Class1(){
this.name="abc";
this.method=function(a){
console.log("这是Class1的参数"+a);
}
};
function Class2(){
Class1.call(this);
// this.name="qwe"
}
var newclass2=new Class2();
newclass2.method("asd"); //这是Class1的参数asd
这样 Class2 就继承Class1了,Class1.call(this) 的 意思就是使用 this对象代替Class1对象调用Class1的方法,那么 Class2 中不就有Class1 的所有属性和方法了吗,Class1对象就能够直接调用Class1 的方法以及属性了,执行结果就是:alert(“cc”);
对的,就是这样,这就是 javaScript 如何来模拟面向对象中的继承的,还可以实现多重继承。
function Ff1(){
this.methodadd=function(a,b){
console.log(a+b)
}
};
function Ff2(){
this.methodjian=function(a,b){
console.log(a-b);
}
};
function Ff3(){
Ff1.call(this);
Ff2.call(this);
};
var shili=new Ff3();
shili.methodadd(2,2); //4
shili.methodjian(5,4); //1
很简单,使用两个 call 就实现多重继承了 。
二、apply()
跟call()的用途是一样的,都是在特定的作用域中调用函数。 只是用法不同于call();
接收参数方面不同,apply()接收两个参数,一个是函数运行的作用域(this),另一个是参数数组。
call()方法第一个参数与apply()方法相同,但传递给函数的参数必须列举出来。
1、语法:
Function.apply(obj,args)方法能接收两个参数
obj:这个对象将代替Function类里this对象
args:这个是数组,它将作为参数传给Function(args–>arguments)
function Student(name,age,grand){
this.name=name;
this.age=age;
this.grand=grand;
};
function Student2(name,age,grand){
Student.apply(this,arguments);
// Student.call(this,name,age,grand);
};
var lili=new Student2("lili",12,"043");
console.log(lili.name); //lili
console.log(lili.age); //12
console.log(lili.grand); //043
apply的一些其他巧妙用法:
Math.min()和Math.max()用法相似。
两个方法用来获取给定的一组数值中的最大值或最小值,但是却不接受数组作为参数。
因为Math.max 参数里面不支持Math.max([param1,param2]) 也就是数组
但是它支持Math.max(param1,param2,param3…),所以可以根据刚才apply的那个特点来解
有两个快捷的方法可以接受数组类型参数:
1 . Math.min.apply(null, arr)
唉?不是不能接收数组类型的参数吗?这是apply方法的特性,apply方法第二个参数为参数的数组,明白了吧,虽然我们传入的是数组参数,但是apply会将数组拆分并传入调用的函数。可以说是比较巧的用法了。
alert(Math.max(2,4,6,9)); //9
alert(Math.max([7,9,9,78]));//NaN
alert(Math.max.apply(null,[7,9,9,78]));//78
三、call()与apply()的区别:
apply和call功能一样,只是传入的参数列表形式不同:如 func.call(func1,var1,var2,var3)
对应的apply写法为:func.apply(func1,[var1,var2,var3])
也就是说:call调用的为单个,apply调用的参数为数组。
四、bind()
自己总结:可以正确的提取方法
正确的提取方法:
var proto1={
name:"abc",
describe:function(){
return "name:"+this.name;
}
};
var func=proto1.describe.bind(proto1);
console.log(func()); //name: abc
由于我们把proto1.describe的值作为函数来调用,,因此现在的this是全局对象window,,而window.describe不存在,,此时就需要用到bind(),,,在调用方法时后面绑定bind(方法的对象),,这样就保证了describe(方法)与对象(proto1)不会失去联系。
五、方法中的this会被掩盖
嵌套函数中:一个方法包含一个普通的函数,如果想在后者的内部访问前者,方法的this却被后者的普通函数this掩盖。。。。
var obj={
name:'zs',
friends:["jone","grace"],
loop:function(){
"use strict"
this.friends.forEach(function(friend){
console.log(this.name+"的朋友是:"+friend);//(1)
})
}
};
obj.loop();
(1)出的this.name中的this是指loop后的function函数。并非obj,,,
解决方案:
方案一:that=this
loop:function(){
"use strict"
var that=this;
this.friends.forEach(function(friend){
console.log(that.name+"的朋友是:"+friend);
})
}
执行结果:
zs的朋友是:jone
zs的朋友是:grace
方案二:bind()
使用bind()给里面变化的this函数绑定一个你想要的,this固定值,,即外面obj对象的this
loop:function(){
"use strict"
this.friends.forEach(function(friend){
console.log(this.name+"的朋友是:"+friend);
}.bind(this));
}
输出结果:
zs的朋友是:jone
zs的朋友是:grace
方案三:forEach()的thisValue
这个方案特定于forEach(),,,里面的第二个参数成为这个函数的第二个参数。
loop:function(){
"use strict"
this.friends.forEach(function(friend){
console.log(this.name+"的朋友是:"+friend);
},this)
}
输出结果:
zs的朋友是:jone
zs的朋友是:grace