看完这篇文章,你将了解:
1.js 函数的五种声明方式
2.js 函数的本质
3.this 和 arguments 是什么
4.树与作用域
5.其他小知识
一、函数的5种声明方式
1:具名函数
function f(x,y){ }
2:匿名函数
var f = function (x,y){ }
3:
var f = function z(x,y){ }
注:这种方式结合了前两种的写法,注意它有一个隐藏的坑(见 其他小知识=>1)
4:对象构造
var f = new Function('x', 'y', 'return x+y')
5:=>简写
var f = (x,y) => { }
二、函数的本质
一句话:函数是一个可以执行代码的对象
从内存图角度讲,js函数的本质如下:
![d863633fa2372639932fb624415dfa12.png](https://img-blog.csdnimg.cn/img_convert/d863633fa2372639932fb624415dfa12.png)
为更进一步说明函数本质就是一个对象,我们甚至可以自己构造一个“函数”对象,这个对象具有函数功能。
![5bfcaf6d6944b2e2dfa5f676c6c1d981.png](https://img-blog.csdnimg.cn/img_convert/5bfcaf6d6944b2e2dfa5f676c6c1d981.png)
三、this和arguments是什么?
前面讲过,函数调用本质上,就是通过函数对象对call方法的调用,该方法参数表如下:
Function.call(this, arguments[0], arguments[1], ...)
可见,this和arguments,都是Function.call( )的参数。
this是call的第一参数;
arguments是call的第二参数起所有参数组成的伪数组,也是函数实际调用时,我们传入的参数表。
事实上,我们每次调用函数
f(1, 2)
相当于执行方法
f.call(undefined, 1, 2)
实例:
![329f2db236b260b9742ecd45c476e331.png](https://img-blog.csdnimg.cn/img_convert/329f2db236b260b9742ecd45c476e331.png)
![b4bf5271ecd560732fc5ae0342b2a53f.png](https://img-blog.csdnimg.cn/img_convert/b4bf5271ecd560732fc5ae0342b2a53f.png)
注:arguments是复数形式,不要忘了s
注2:一些Java学习者,看见this难免见名生义,认为它就是“当前对象”;但通过以上分析我们可以看到,JavaScript中this并非对象,它就是一个参数而已。
四、树与作用域
与作用域有关问题容易出错,我们可以画一棵树来描述作用域关系。
1.预备知识a:变量提升
var a = 1在代码中做了两件事:既声明(var a),又赋值(a = 1)。等价于
var a //声明
a = 1 //赋值
变量提升就是将这两件事拆开做:保持a = 1位置不变,将var a提升到所属作用域的最上方。
2.预备知识b:一个函数就是一块作用域,变量的访问遵循就近原则
![11607ff81090a425641644d9ebab736d.png](https://img-blog.csdnimg.cn/img_convert/11607ff81090a425641644d9ebab736d.png)
3.用树分析作用域逻辑
在全局范围下,先做一次变量提升,然后把所有声明变量与函数名维护为一个变量数组,这个数组就是一个根节点,里面的变量都是全局变量。
然后从根节点的所有函数出发,每个函数里继续做变量提升,维护变量数组 .... 递归地执行类似操作,就构成了一棵作用域"树"
![78926921754e64e1f6a347cb8cbf61d6.png](https://img-blog.csdnimg.cn/img_convert/78926921754e64e1f6a347cb8cbf61d6.png)
作用域“树”的用法:
每当我们访问一个变量时,先看所在作用域是否有该变量,有→直接访问,没有→从父亲结点的作用域访问,依此类推。
q:如果顺着父亲结点一直没有找到访问变量,该怎么办呢?
a:这种情况,它会声明全局变量并赋值
![007d4c7912111141e31a099d0792ed28.png](https://img-blog.csdnimg.cn/img_convert/007d4c7912111141e31a099d0792ed28.png)
4. 4个作用域问题
Q1:
![fa9b1b340f6cd4e2c8d085e94cd105bf.png](https://img-blog.csdnimg.cn/img_convert/fa9b1b340f6cd4e2c8d085e94cd105bf.png)
a1:
![64f5f71f37b44758b9dc53f24dbfe2c3.png](https://img-blog.csdnimg.cn/img_convert/64f5f71f37b44758b9dc53f24dbfe2c3.png)
Q2:
![1d723c2b4f87827e8eb551579572c1d8.png](https://img-blog.csdnimg.cn/img_convert/1d723c2b4f87827e8eb551579572c1d8.png)
a2:
![da4dfbaacad06521a0e59a0f1c96b4cb.png](https://img-blog.csdnimg.cn/img_convert/da4dfbaacad06521a0e59a0f1c96b4cb.png)
Q3:
![039e11376d6c14d6ddaaf1078cb5633b.png](https://img-blog.csdnimg.cn/img_convert/039e11376d6c14d6ddaaf1078cb5633b.png)
a3:
![10d102aa128f4879445c9a0b1bfbfcfb.png](https://img-blog.csdnimg.cn/img_convert/10d102aa128f4879445c9a0b1bfbfcfb.png)
Q4:
![442c9831d8e6f6bda47851d6a9380f65.png](https://img-blog.csdnimg.cn/img_convert/442c9831d8e6f6bda47851d6a9380f65.png)
a4:
![96d3b8cd82410d619591cadd44929754.png](https://img-blog.csdnimg.cn/img_convert/96d3b8cd82410d619591cadd44929754.png)
五、其他小知识
1.函数相关的一个坑
下图中,我们能访问y,不能访问y2
![6e2d1f8e5ef4e3b561fa67b7451124dc.png](https://img-blog.csdnimg.cn/img_convert/6e2d1f8e5ef4e3b561fa67b7451124dc.png)
2.控制台按住"shift + 回车"可以不执行结果换行,继续写代码。
3.什么叫做“stack overflow”?
就是栈上溢,指压栈次数超过最大限制。
![0104ae53948becc8148524adb625ca54.png](https://img-blog.csdnimg.cn/img_convert/0104ae53948becc8148524adb625ca54.png)
4.什么是闭包?
如果一个函数,使用了它范围外的变量,那么(这个函数 + 这个变量)就是闭包。