js函数

函数是什么?

函数在js中是以字符串的形式储存起来的(这会带来效率问题吧?)

在js中函数也是个对象,执行的代码块以字符串的形式保存在对象某个地方,使用f()就是调用这块代码。
传统的调用方式是使用.call()执行函数。

声明方式

具名函数

就是有名字的函数

1
2
function f(){
}

具名函数的声明,初始化,赋值都会被变量提升至顶部

匿名函数

就是没有名字的函数

1
2
var a = function (){
}
1
2
3
4
a() //报错
var a = function (){
console.log(666)
}

用此种方式,是以变量提升的方式,声明,初始化被提升至顶部,在声明前调用会错误。

具名函数赋值

1
2
3
var a = function b(){
console.log(666)
}

这种方式其实等于匿名函数,b不能被使用,但能在函数内部使用。(BUG js)

函数对象

1
2
3
4
5
6
new Function('x','y','return x+y')

//或者
var n =1
var z = new Function('x','y','return x+'+n+'+y')
z(1,2) //返回4

箭头函数

1
(x,y) => x+y

这回直接返回 x+y,如果参数只有一个,可以省略前面的括号,后面只有一个个表达式可以省略后面的大括号,箭头函数总是匿名函数

相关函数

f.name

得到函数名
匿名函数会得到指向它的变量,具名函数赋值会得到具名函数的值……
如果使用Function()声明,总是返回anonymlus,表示匿名的

f.call()

f.call()就是执行函数体
第一个参数为执行的对象,其余为函数的参数,这是js真正的调用方法,f()可以说只是一种语法糖

call()的第一个参数可以用this得到,后面的参数可以用arguments得到

this

在普通模式,如果传入的是null或者undefined,则默认为Window
,如果开启严格模式,则不会自动转变,传入什么就是什么,严格模式可以使用use strict开启。

严格模式中,参数的类型转换不会发生,比如这样

1
2
3
4
5
function f(){
'use strict'
console.log(this)
}
f.call(1)

本来1不是对象,但call需要第一个是对象,就会把1自动装箱成Number对象,使用’use strict’会禁用参数的自动装箱

arguments

arguments是一个伪数组,虽然是数组的形式,但_proto_指向Object,不指向Array。
它储存着函数调用时所有的实参。

函数调用过程

函数调用过程是以栈的形式进行调用,先进后出,在我们递归调用时,尤其要注意栈空间的占用,否则可能溢出(stack Overflowd网站的名字,233),如果递归时不会使用函数内的变量,会进行尾递归优化,不再存储函数内的变量,减少栈空间调用。

作用域(scope)

函数内会构成一个新的作用域,多个函数的嵌套,构成了一棵作用域树

这里我们就需要区别几种声明变量的方式

  • 不加关键字声明
    因为作用域是一棵树,找不到会向上找,直到找到window对象,如果window对象也不具有该值,就认为是为window设置键值对,这就创建了全局变量
  • var 声明
    var 声明会被提升至该作用域顶部,并在顶部初始化为undefined
  • let
    let声明同样会被提升至顶部,但初始化和赋值只会在进入let所在区块进行,未在所在区块的使用都被认为是非法的