每个函数除了声明时定义的形参外,还接收两个附加参数,即 arguments 和 this 。this 在面向对象编程过程中非常重要,而它的值其实取决于调用模式,因为不同的模式调用在如何初始化关键参数 this 上存在差异。
函数调用在 JavaScript 中有四种模式:方法调用模式,函数调用模式,构造器调用模式,apply调用模式。
1.方法调用模式
当该函数保存在一个对象属性上,我们称它为对象的方法,当方法被调用时,this 被绑定到该对象
// 创建一个对象,并保存一个函数为它的方法
var myBook = {
book1: "javascript",
book2: "vuejs",
loadMybook: function(){
console.log("I have this book: " + this.book1)
this.book2 = "javascript高级程序设计"
console.log(this.book2)
}
}
// 当该方法被调用时,this 绑定对象 myBook
// 即当方法被调用时,方法可以使用 this 访问自己所属对象
// 可从对象中取值并对对象的值进行修改
myBook.loadMybook()
// 结果为
// I have this book: javascript
// javascript高级程序设计
2.函数调用模式
当一个函数并非一个对象的属性时,则被当作函数来调用
// 声明一个函数 add
function add(a, b){
console.log(this)
return a + b
}
调用函数 add ,即可输出 this 值以及计算结果,如下图所示
由此可知,当在函数调用模式中,该函数的 this 被绑定到全局对象 Window 。这种指向将造成如果一个函数A 有一个内部函数B,那么 函数B 将无法通过 this 访问函数包含A函数对象的变量或方法。解决办法为将 A 的 this 赋值于一个变量,然后 B 可通过访问这个变量访问到 this , 按照约定将这个变量命名为 that
myNum = {
num1: 2,
num2: 3,
addNum: 0,
sum: function(){
var that = this
var add = function(){
console.log(this) // this 指向 Window
console.log(that) // that 指向 myNum
that.addNum = that.num1 + that.num2
console.log(that.addNum)
}
add()
}
}
// 以方法的形式调用 sum
myNum.sum()
运行结果如下
3. 构造器调用模式下函数 this 指向
如果在一个函数前带上 new 来调用,则会创建一个连接到该函数的的 proptype 的新对象,同时 this 绑定到该对象上,即创建一个实例后,构造器中的 this 指向实例本身
// 创建一个名为 Book 的构造器函数,带有一个 name 属性
var Book = function(name){
this.name = name
}
// 给所有实例提供一个方法
Book.prototype.get_name = function(){
console.log(this.name)
}
// 构建一个实例
var myBook = new Book("javascript")
// 调用 get_name 方法
myBook.get_name() // 控制台 打印 javascript
4. Apply 调用模式
apply 方法接收两个参数,第一个是要绑定的 this 的值,第二个是一个参数数组。
因此,apply 方法可以让我们选择 this 的值
// 构建一个包含 name 属性的对象
var anotherBook = {
name: "python"
}
// 此对象并未继承 Book.prototype ,但以然可以调用前例中 get_name 方法
var book = Book.prototype.get_name.apply(anotherBook) // 控制台输出 python