函数是对象
在JS中,函数只是一种对象,尽管它看起来和对象很不一样
如何定义一个函数
- 具名函数
function 函数名(形式参数){
语句
return 返回值
}
- 匿名函数
匿名函数与具名函数的区别就在于是否有函数名
let a = function (形式参数){
语句
return 返回值
}
这里函数一定要将其地址赋予a,否则,该函数由于没有函数名,也未被引用而消失!
- 箭头函数(没有this与arguments)
let 函数名 = (形式参数) => (
语句
return 返回值
)
- 总结
其实,我们也可以通过一种不常用的方法构造函数
let fn = new Function ('形式参数1','形式参数2','语句' 'return 返回值')
通过以上语句,我们可以看出 函数 是由 Function 构造出来的
函数的调用
- fn 与 fn() 的区别
let fn = function(){
console.log('hi')
}
//fn
//fn()
- fn 指向的是 函数(对象)在内存中的 地址
- fn() 则表示调用函数
函数的要素 —— 调用时机
一个函数的调用时机不同,结果就不同
函数的要素 —— 作用域与闭包
作用域遵循 ‘就近原则’ 如图中f3 中的 变量a 就是 let a = 2 的a,
a的值为22
f3 与 let a = 2 中的 a 组成了一个 闭包
函数的要素 —— 形式参数
形式参数就相当于数学中的设 x y ,他并没有实际意义
function add(x,y){
return x+y
}
上面的 x y 就是形式参数,他没有意义,只有当我们调用它时,形式参数才会变成 实际参数
add.call(undefined,1,2)
其中,1,2,分别是 x,y 的实际参数
我们可以将形式参数 认为是变量声明,它等同于以下代码
function add(){
var x = arguments[0]
var y = arguments[1]
return x+y
}
函数的要素 —— 返回值
每个函数都有返回值,若未写return ,则默认返回 undefined
function hi(){
return console.log('hi')
}
// 返回 console.log('hi') 的值,即undefined
函数的要素 —— 调用栈
- 什么是调用栈
JS 引擎在调用一个函数前,需要把函数所在的环境push到一个数组(压栈),这个数组叫做调用栈,等函数执行完了,九八环境pop出来(弹栈),return 到之前的环境,继续执行后面的代码
- 爆栈
以递归函数为例
function f(n){
return n !== 1 ? n*f(n-1) : 1
}
此函数 压了n次栈 , 弹了n次栈, 当n大于浏览器的最大数量时,程序就会报错
函数的要素 —— 函数提升
- 什么是函数提升
具名函数不管写在哪里,他都会自动跑到第一行
- 什么不是函数提升
当函数赋给一个变量时,不会提升
函数的要素 —— arguments 与 this
每个函数都有arguments 与 this , 除了箭头函数
对于箭头函数来说,this永远是window
- arguemnts
arguments 是一个伪数组 ,它没有 数组 的原型,只有对象的原型
- this
this === window
- this 的 原理
我们先来看一段代码
let person = {
name: 'hht',
sayHi(){
console.log(this.name)
}
}
//person.sayHi()
//hht
如果我们不用this,那么此段代码就应该写成
let person = {
name: 'hht',
sayHi(p){
console.log(p.name)
}
}
//person.sayHi(person)
//hht
this 的原理就是在帮你省略了一个形式参数p,在调用函数时,将sayHi前的person 复制一份到()中
- 自定义this
如果我们让JS自动帮我们调用this,有时会发生歧义,所以我们也可以自定义this
let person = {
name: 'hht',
sayHi(){
console.log(this.name)
}
}
//person.sayHi.call({name:'jack'})
//jack
function add(x,y){
return x+y
}
// add.call(undefined,1,2)
// add.apply(undefined,[1,2])
- this 可以解决的问题
this 可以帮我们解决 一些问题 ,例如 我们在使用构造函数时,我们并不知道构造出来的函数的名字,此时,我们就可以使用this
- 绑定this 及 其他参数
let fn = function (x,y){
console.log(this.name),
console.log(x,y)
}
let fn2 = fn.bind({name:'hht'},1)
- this 的自动封装问题
我们可以看到,当我们传一个 非对象 时,this会自动将其封装
解决办法: 加一行 'use strict'
function fn(){
'use strict'
console.log(this)
}
立即执行函数
在ES5 时代,还没有let, var声明的变量会自动变为全局变量,所以我们必须要使用以下方法来解决这个问题, 让 var 声明的变量变成 局部变量
! function(){
var a = 2
}()
// ! ~ () + - 这些运算符号放在匿名函数前都可以
// 但是推荐使用 !
在ES6 时代,我们用let就可以解决这问题
{
let a = 2
}