js函数
函数是什么?
函数在js中是以字符串的形式储存起来的(这会带来效率问题吧?)
在js中函数也是个对象,执行的代码块以字符串的形式保存在对象某个地方,使用f()就是调用这块代码。
传统的调用方式是使用.call()
执行函数。
声明方式
具名函数
就是有名字的函数
1 | function f(){ |
具名函数的声明,初始化,赋值都会被变量提升至顶部
匿名函数
就是没有名字的函数
1 | var a = function (){ |
1 | a() //报错 |
用此种方式,是以变量提升的方式,声明,初始化被提升至顶部,在声明前调用会错误。
具名函数赋值
1 | var a = function b(){ |
这种方式其实等于匿名函数,b不能被使用,但能在函数内部使用。(BUG js)
函数对象
1 | new Function('x','y','return x+y') |
箭头函数
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 | function f(){ |
本来1不是对象,但call需要第一个是对象,就会把1自动装箱成Number对象,使用’use strict’会禁用参数的自动装箱
arguments
arguments是一个伪数组,虽然是数组的形式,但_proto_指向Object,不指向Array。
它储存着函数调用时所有的实参。
函数调用过程
函数调用过程是以栈的形式进行调用,先进后出,在我们递归调用时,尤其要注意栈空间的占用,否则可能溢出(stack Overflowd网站的名字,233),如果递归时不会使用函数内的变量,会进行尾递归优化,不再存储函数内的变量,减少栈空间调用。
作用域(scope)
函数内会构成一个新的作用域,多个函数的嵌套,构成了一棵作用域树
这里我们就需要区别几种声明变量的方式
- 不加关键字声明
因为作用域是一棵树,找不到会向上找,直到找到window对象,如果window对象也不具有该值,就认为是为window设置键值对,这就创建了全局变量 - var 声明
var 声明会被提升至该作用域顶部,并在顶部初始化为undefined - let
let声明同样会被提升至顶部,但初始化和赋值只会在进入let所在区块进行,未在所在区块的使用都被认为是非法的