在js中,每一个函数都是Function类型的实例,都是对象
定义函数
以函数声明的方式定义
function sum(a,b){
return a + b
}
以函数表达式定义
let sum = function(a,b){
return a + b
}
JavaScript引擎在任何代码执行之前,会先读取函数声明,并在执行上下文中生成函数定义。而函数表达式必须等到代码执行到它那一行,才会在执行上下文中生成函数定义
console.log(sum(1,2)) // 正常执行
function sum(a,b){
return a + b
}
console.log(sum(1,2)) // 报错
let sum = function(a,b){
return a + b
}
以箭头函数的方式定义
let sum = (a,b) => a + b
箭头函数
箭头函数是ES6新增的一种定义函数的方式。箭头函数在很大程度上与使用函数表达式定义的函数是相同的,但也有一些不同之处
如果只有一个参数时,可以不使用括号
let sum = x =>{ return 3*x }
箭头函数也可以不使用大括号,此时箭头后面只能包含一行代码,同时隐式的会返回这行代码的值
let sum = (x)=> 3*x
箭头函数不能使用arguments、super和new.target,不能用作构造函数,不包含prototype属性
函数参数
在js中,函数并不关心参数的个数,也不关心参数的类型。之所以会这样,是因为在编译时函数参数在内部表现为一个数组。函数被调用时总会接收一个数组,但函数并不关心这个数组中包含什么
在使用function定义的(非箭头)函数时,可以在函数内部可以访问到一个arguments对象,从中取出传入的参数
function test(a,b){
console.log(arguments)
}
箭头函数没有arguments
arguments不反应默认参数,arguments只和调用函数时相关
function sum(a = 1,b = 2){
console.log(arguments)
}
默认参数作用域与暂时性死区
给多个参数设置默认值就和使用let按顺序定义变量一样。因此:
- 后定义的参数可以使用先定义的
function sum(a= 1, b = a){
return a+b
}
- 先定义的不能使用后定义的
function sum(a= b, b = 1){
return a+b
}
- 不能使用函数体中定义的变量
function sum(a= 1, b = c){
let c = 2
return a+b
}
扩展参数
let values = [1,2,3,4]
function sum(){
let sum = 0
for(let i = 0;i<arguments.length;++i){
sum += arguments[i]
}
return sum
}
sum(...values) // 将传入的参数扩展
参数收集
function sum(...data){
console.log(data)
}
sum(1,2,3) // [1,2,3] // 将入参收集在一个数组里
function sum1(a,...data){
console.log(a)
console.log(data)
}
sum1(1,2,3,4) // 1 [2,3,4]
this
this是函数内部一个重要的对象,箭头函数和普通函数的this指向是有所不同的
window.color = 'red'
const o = {
color:'blue'
}
function sayColor(){
console.log(this.color)
}
sayColor() // red
o.sayColor = sayColor
o.sayColor() // blue
在普通函数中,this指向的是把函数当做方法调用时的上下文对象
window.color = 'red'
const o = {
color:'blue'
}
let sayColor = ()=> console.log(this.color)
sayColor() // red
o.sayColor = sayColor
o.sayColor() // red
在箭头函数中,this指向的是定义函数时的上下文对象
new.target
函数既可以作为普通函数调用,也可以作为一个构造函数用于创建新对象。当使用new调用时,new.target指向被调用的构造函数;当作为普通函数调用时,为undefined
函数的属性和方法
length
定义函数时声明的参数个数
function sum(a,b){
}
console.log(sum.length) // 2
prototype
prototype是保存引用类型所有实例方法的地方,这意味着toString()等方法全都在这上面,进而由所有实例共享
prototype是不可枚举的,所以不能使用for-in循环出这个属性
apply()、call()和bind()
在一般情况下,标准函数的this是由函数被调用时决定的,但js中也有显式的控制this的方法:apply()、call()、bind()
apply()
apply接收一个参数数组
function greet(address,school){
console.log(this.name,this.age,address,school)
}
const stu = {
name:'momo',
age:18
}
greet.apply(stu,['beijing','xtu']) // momo 18 beijing xtu
call()
call与apply类似,区别在于传参的时候只能一个一个传
function greet(address,school){
console.log(this.name,this.age,address,school)
}
const stu = {
name:'momo',
age:18
}
greet.call(stu,'beijing','xtu') // momo 18 beijing xtu
bind()
bind会返回一个新函数,这个新函数永久的指向被传入的第一个参数
function greet(address,school){
console.log(this.name,this.age,address,school)
}
const stu = {
name:'momo',
age:18
}
const _greet = greet.bind(stu)
_greet('beijing','xtu') // momo 18 beijing xtu