调用一个函数会暂停当前函数的执行,传递控制权和参数给新函数。除了声明时定义的
形式参数(parameters)
,每个函数还接收两个附加参数:this
和arguments(实际参数)
。参数this
的值在面向对象中取决于调用的模式。
当实际参数大于形式参数时并不会产生错误,多余的实际参数会被忽略,
当实际参数小于形式参数时缺失的部分会抛出undefined
在JS中函数的调用有四种模式:
- 方法调用模式
- 函数调用模式
- 构造函数调用模式
- apply调用模式
一、方法调用模式
当一个函数被保存做对象的一个属性时,我们称作方法.当方法被调用时,
this
会被绑定到该对象.如果调用表达式包含一个提取属性的动作(即".
“或”[]
"),那么它就是被当做一个方法调.
// 创建obj对象,它有一个value属性和increment方法
let obj = {
value: 0,
increment: function (inc) {
this.value += typeof inc === 'number' ? inc : 1
// 调用increment方式时传入的参数是数字,则参数+=value,否则+=1
}
}
obj.increment();//初始0
console.log(obj.value);//0+=1
obj.increment(2);//如果是数字经过上面两层操作后1+=2
console.log(obj.value);//3
方法可以使用
this
访问自己所属的对象,所以它能从对象中取值或对对象进行修改.this
到对象的绑定发生在调用的时候.这个"超级"延迟绑定使得函数可以对this
高度复用.通过this
可取得它们所属对象的上下文的方法称为公共方法(public method)
二、函数调用模式
当一个函数并非对象的属性时,那么它就是被当作一个函数来调用的:
let sum = function (a, b) {
console.log(this);
return a + b
}
console.log(sum(3, 4));
以此方式调用函数时,
this
会被绑定到全局对象.这个是语言设计上的错误,倘若语言设计正确,name
当内部函数被调用时,this
应该仍然绑定到外部函数的this
变量.这个设计错误的后果是方法不能利用内部函数来帮助它工作,因为内部函数的this
被绑定了错误的值,所以不能共享该方法对对象的访问权.
解决方法:给该对象定义一个变量并赋值为this
,那么内部对象就可以通过这个变量访问到this
,这里示范为that
.
// 创建obj对象,它有一个value属性和increment方法
let obj = {
value: 0,
increment: function () {
// 调用increment方式时传入的参数是数字,则参数+=value,否则+=1
this.value += typeof inc === 'number' ? inc : 1
let that = this
// 内置对象
let sum = function (a, b) {
that.value = a + b
return
}
sum(3, 4);
},
}
obj.increment();//初始0
console.log(obj.value);//7,如果不加变量转换this指向则为1
三、构造器调用模式
如果在一个函数面前加上
new
来调用,那么背地里会创建一个连接到该函数的prototype
成员的新对象,同时this
会被绑定到那么新对象上.
//创建一个名为Quo的构造器函数,它构造一个带有status属性的对象.
let Quo = function (string) {
this.status = string
}
console.log(Quo.prototype);
//给Quo的所有实例提供一个名为get_status的公共方法
Quo.prototype.get_status = function () {
return this.status
}
console.log(Quo.prototype);//出现get_status方法
//构造一个Quo实例
let myQuo = new Quo('confused')
console.log(myQuo.status);//confused
console.log(myQuo.get_status());//confused
console.log(myQuo);
console.log(typeof myQuo.get_status);//function
一个函数,如果创建的目的希望是结合
new
前缀来调用,那么就被称作构造器函数,按照约定,它们会被保存在以大写格式命名的变量里.如果调用构造器函数时没有在前面加上new
,那么即没有编译时警告,也没有运行时警告,所以大写约定非常重要.
但不推荐使用这种形式的构造器函数.
四、Apply调用
Apply
方法让我们构造一个参数数组传递给调用函数,它允许我们选择this的值.
Apply
方法接收两个参数,第一个是要绑定给this的值,第二个是参数数组
let person = {
firstName: "Bill",
lastName: "Gates",
}
let person1 = ["+", 4]
let person2 = {
fullName: function (item, item2) {
return this.firstName + item + item2
}
}
let x = person2.fullName.apply(person, person1)
console.log(x);//Bill+4
试试挂到prototype
//构造一个包含status成员的对象
let staObj = {
status: '山竹'
}
//staObj并没有继承来自Quo.prototype,但可以在staQuo上调
// 用get_status方法,尽管staObj没有一个名为get_sta的方法
let sta = Quo.prototype.get_status.apply(staObj)
console.log(sta);//山竹