看完这篇文章,你将了解:
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){ }
注:这种方式结合了前两种的写法,注意它有一个隐藏的坑(见后文)
4:对象构造
var f = new Function('x', 'y', 'return x+y')
5:=>
var f = (x,y) => { }
二. 函数的本质
一句话:函数是一个可以执行代码的对象
为说明函数本质是一个对象,我们甚至可以自己构造一个“函数”对象,这个对象具有函数功能。
三. 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)
实例:
注: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:一个函数就是一块作用域,变量的访问遵循就近原则
3.用树分析作用域逻辑
在全局范围下,先做一次变量提升,然后把所有声明变量与函数名维护为一个变量数组,这个数组就是一个根节点,里面的变量都是全局变量。
然后从根节点的所有函数出发,每个函数里继续做变量提升,维护变量数组 .... 递归地执行类似操作,就构成了一棵作用域"树"
作用域“树”的用法:
每当我们访问一个变量时,先看所在作用域是否有该变量,有→直接访问,没有→从父亲结点的作用域访问,依此类推。
q:如果顺着父亲结点一直没有找到访问变量,该怎么办呢?
a:分两种情况,无 var 声明它会声明全局变量并赋值;有 var 声明它会在当前作用域生成局部变量
- 4个作用域问题
Q1:
a1:
Q2:
a2:
Q3:
a3:
Q4:
a4:
五. 其他小知识
1.函数相关的一个坑
下图中,我们能访问y,不能访问y2
2.控制台按住"shift + 回车"可以不执行结果换行,继续写代码。
3.什么叫做“stack overflow”?
就是栈上溢,指压栈次数超过最大限制。
比如:递归引发栈上溢
4.什么是闭包?
如果一个函数,使用了它范围外的变量,那么(这个函数 + 这个变量)就是闭包。
暂无评论