JavaScript函数中的this参数一直是初学者难以理解的东西,这里就this在不同调用方式中的指向问题做一下归纳
除了声明时定义的形式参数,每个函数接受两个附加的参数:this和arguments,参数this在面向对象编程中非常重要,它的值取决于调用的模式。
在JavaScript中一共有四种调用模式:方法调用模式、函数调用模式、构造器调用模式、apply调用模式
以上的引用来自《JavaScript语言精粹》中关于函数调用的部分
说的非常清楚;this参数随着调用方式的不同而指向不同的对象
方法调用模式
当一个函数被保存为对象的一个属性时,我们称它为一个方法。当一个方法被调用时,this被绑定到该对象
var fn1 = {
name : "function",
getName : function () {
console.log(this.name)
}
}
fn1.getName() //function
函数调用模式
当一个函数并非作为一个对象的属性时,它就是被当做函数来调用的;这种情况下this指向全局对象
var fn1 = {
name : "function",
getName : function () {
var inner = function () {
console.log(this.name)
}
inner()
}
}
fn1.getName() //"" (因为window.name = "")
以上情况是语言设计上的一个错误,这使得方法无法利用内部函数来帮助工作
不过有一个比较简单的方法可以解决此类错位:
1)将关键字this赋值给另一个变量,使用新的变量来规避这种设定
2)var that = this;
var fn1 = {
name : "function",
getName : function () {
var that = this; //使用新的变量来访问this
var inner = function () {
console.log(that.name) //此处用that访问属性
}
inner()
}
}
fn1.getName() //function
构造器调用模式
如果一个函数前面带上new来调用,那么背地里将会创建一个连接到该函数的prototype成员的新对象,同时this会被绑定到那个新对象上
如果穿件的目的就是希望结合new前缀来调用,那它就被称为构造器函数。按照约定,它们保存在以大写格式命名的变量里
function fn1 () {
this.name = "function";
this.getName = function () {
console.log(this.name);
}
}
var NewFunc = new fn1(); //此处的NewFunc首字母按照约定大写
NewFunc.getName(); //function
这部分牵扯到的构造函数、原型等原理比较复杂,我也还没有彻底理解,就不在这里多说了╮(╯▽╰)╭
Apply调用模式
apply方法让我们构建一个参数数组传递给调用函数。它也允许我们选择this的值。apply方法接受两个参数,第一个是要绑定给this的值,第二个就是一个参数数组
//这个例子我们上面看过
//如果用inner()调用,最终结果是this指向window,打印出空字符串""
var fn1 = {
name : "function",
getName : function () {
var inner = function () {
console.log(this.name)
}
inner.apply(fn1) //用apply方法将this强行指向外部函数fn1
}
}
fn1.getName() //function
这个例子是上面函数调用中的例子,当时我们用的是函数调用模式inner()
现在我们在调用时用inner.apply(fn1)
,强行将this指向fn1,结果就变成了我们想要的function