开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第1天
函数是什么
JS中的函数是对象。对象拥有一个连接到原型的隐形链接,而函数对象连接到Function.prototype,Function.prototype连接到Object.prototype。每个函数在创建时会附加两个隐藏属性:函数的上下文和实现函数行为的代码。函数与对象的不同之处在于可以被调用。
函数在创建时也会随之配一个prototype属性,prototype属性的值是拥有一个contructor属性的且contructor属性的值即为该函数的对象。
函数中的this
调用函数时,传入函数的参数除了函数声明时定义的形参,还有两个附加参数:this和arguments,this的值取决于函数的调用模式。ES5 引入了bind方法来设置函数的 this值,而不用考虑函数如何被调用的。ES6 引入了箭头函数,箭头函数不提供自身的 this 绑定(this 的值将保持为闭合词法上下文的值)
函数的调用模式有以下几种:
- 方法调用模式
- 函数调用模式
- 构造器调用模式
- apply/call 调用模式
(1) 方法调用模式
当函数作为对象的属性时,就称这个函数为方法。当调用方法时,this被绑定到所属的对象上面,绑定操作发生在方法调用时。方法通过this实现对读取对象的属性以及操作对象。
const myObject = {
value: 0,
increment: function(inc) {
this.value += typeof inc === 'number' ? inc : 1
}
}
myObject.increment()
console.log(myObject.value) // 1
myObject.increment(2)
console.log(myObject.value) // 3
(2)函数调用模式
当函数不作为对象的属性时,就是默认的函数调用模式,调用时this被绑定到全局对象(在浏览器中全局对象是window,node中是globalThis)
function f1() {
return this
}
f1() === window // true
const myObject = {
value: 1,
}
myObject.double = function(){
...
const helper = function(){
this.value = this.value * 2
}
...
helper()
}
let value = 1
myObject.double()
console.log(myObject.value) // 1
console.log(value) // 2
即使是调用方法内部的函数,this仍然被绑定到全局对象。于是方法不能利用内部的函数为自己工作,因为内部函数被绑定到了全局对象,因此不能共享方法对对象的访问权利。
解决方法:方法中定义一个变量指向this(this指向对象),那么内部函数就可以通过该变量访问到对象。
const myObject = {
value: 1,
}
myObject.double = function(){
...
const that = this
const helper = function(){
that.value = that.value * 2
}
...
helper()
}
myObject.double()
console.log(myObject.value) // 2
(3)构造器调用模式
如果在调用函数时前面加上关键字new,那么该函数就作为构造器函数,会返回一个新对象,并且函数中的this指向创建的新对象。
const Quo = function(s){
this.status = s
}
const myQuo = new Quo("hello")
console.log(Quo.status) // hello
(4)apply/call 调用模式
apply方法与call方法允许我们选择this的值。apply方法接收2个参数,第一个是要绑定给this的值,第2个参数是一个参数数组。call方法与apply方法类似,不同的是call接收一个参数列表,而 apply方法接收一个参数的单数组。
const arr = [1,2,3]
arr.push.apply(arr, [4,5,6])
console.log(arr) // [1,2,3,4,5,6]
arr.push.call(arr, 7,8,9)
console.log(arr) // [1,2,3,4,5,6,7,8,9]
应用apply/call,我们可以调用其他对象中的方法
const Quo = function(s){
this.status = s
}
Quo.prototype.getStatus = function(){
return this.status
}
const myObject = {
status: "It's OK"
}
const status = Quo.prototype.getStatus.apply(myObject)
console.log(status) // "It's OK"