1. 函数声明和函数表达式有什么区别?
函数声明:function fn(){};
函数表达式:var fn=function(){};
区别: 1. 函数声明构造的函数要有函数名称。函数表达式可以是匿名函数。
2. 函数声明可以变量提升,所以函数可以在声明前调用。而函数表达式不可以。(如图)
2. 什么是变量的声明前置?什么是函数的声明前置?
- 变量声明前置:所谓的变量声明前置就是在一个作用域块中,所有的变量都被放在块的开始出声明(如图)
- 函数声明前置:对于函数声明,js解析器会优先读取,确保在所有代码执行之前声明已经被解析,而函数表达式,如同定义其它基本类型的变量一样,只在执行到某一句时也会对其进行解析。(如图)
3. arguments 是什么?
- arguments不能够创建,是函数自身的参数,只有当函数开始执行是才能使用
虽然arguments的使用方法,很像数组,但是它并不是数组。
4 .函数的重载怎样实现
JS的函数定义可以指定形式参数名称,多多少少我们会以为js至少可以支持参数个数不同的方法重载,然而遗憾的是这仅仅是一个假象,js所有的参数都是以arguments传递过去的,这个参数类似于数组,在函数调用的时候,所有的实参都是保存在了这个数据结构里面,我们定义函数的时候所指定的形式参数其实是为这个数据结构里面的数据定义一个快捷的访问方式。也就是说js所有的函数都是支持无限个参数的,加上数据类型是弱类型,那么JS的函数除了名称就真的没有方法区别了?
办法总是有的,我们可以利用JavaScript中的特殊对象arguments来模拟函数重载。用它来判断传入参数的个数或类型以区分
5. 立即执行函数表达式是什么?有什么作用?
- 执行函数表达式是什么
(function(){alert(‘我是匿名函数’)}()); // 用括号把整个表达式包起来
(function(){alert(‘我是匿名函数’)})(); //用括号把函数包起来
- 作用:
一是不必为函数命名,避免了污染全局变量;
二是函数内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。
6. 什么是函数的作用域链
作用域就是变量与函数的可访问范围,即作用域控制着变量与函数的可见性和生命周期。
在JavaScript中,变量的作用域有全局作用域和局部作用域两种。
在代码中任何地方都能访问到的对象拥有全局作用域
局部作用域一般只在固定的代码片段内可访问到,最常见的例如函数内部,所有在一些地方也会看到有人把这种作用域称为函数作用域
在JavaScript中,函数也是对象,实际上,JavaScript里一切都是对象。函数对象和其它对象一样,拥有可以通过代码访问的属性和一系列仅供JavaScript引擎访问的内部属性。其中一个内部属性是[[Scope]],由ECMA-262标准第三版定义,该内部属性包含了函数被创建的作用域中对象的集合,这个集合被称为函数的作用域链,它决定了哪些数据能被函数访问。
-
举例:
1.分析原因:
第一步:首先定义了一个全局变量a,并且将1赋值给这个a;
第二步:然后建立了一个函数fn(),在函数fn里面定义了局部变量b,并且赋值2给b;
第三步:求fn2()的值,并且定义了fn2()函数,里面是console.log(a)和console.log(c);
第四步:在函数fn中定义了局部变量c并赋值3给c;
第五步:求函数fn();
那么,在这中间发生了什么呢?
1.变量提升,全局变量a的声明提升到最上面变成var = a;a = 1;
2.函数fn()中的局部变量b和c的变量提升到fn()的最上面变成var b;var c;
3.然后函数fn2提升到var b;var c;的下面,后面接着就是求fn2();
4.变量的赋值在函数fn()的最底下:b = 2; c = 3;
5.求fn()的值,也就是fn2()的值;
6.执行的顺序是从上到下的,整个函数变成了如下代码
这个函数中的作用域链是这样的:
1.从上诉可知这个函数的作用域有三个,互成链条,分别是(从外到内)①:全局作用域;②:fn()作用域;③:fn2()作用域
2.执行函数fn2()后,首先在函数fn2()中console.log(a),fn2()就在自身域中找a,没有找到就到上面一层也就是fn()中找a,也没有找到,于是就到全局变量中找a,得到a已经被声明,并且值为1,所以得到a为1;
3.然后fn2()中console.log(c),c在fn2()作用域中也没有找到,就到上一层fn()作用域中找c,而c此时已经被声明但是并未赋值,所以console.log(c)会得到undefined;
4.执行完函数fn2()得出结果后,fn2()被销毁,得出的值变为fn()的值;
上面所诉的就是一个函数的作用域链,总结来说就是,某个函数寻求变量的时候,在自身作用域中找不到就会到上一层作用域去找,一直到全局变量为止,这一个个的作用域连接起来就是作用域链;
代码练习
1. 以下代码输出什么?
1、在函数体内部可以通过arguments对象来访问传递给函数的每一个参数。
2、函数不介意传递进来多少个参数,也不在乎传进来的参数是什么类型,如果没有传递值的命名参数将自动被赋予undefined值。
3、arguments的值永远与对应命名的参数的值保持同步。
2. 写一个函数,返回参数的平方和?
3 .如下代码的输出?为什么 ?
变量提升:
var a;
console.log(a);
a=1;
console.log(b);
a被声明但没有赋值所以第一个undefined;
b没有被声明报错;
4. 如下代码的输出?为什么
sayName函数声明,跟变量声明提前一样,也会进行函数声明前置。所以sayName的函数打印结果为hello world
saAge是函数表达式,不会进行声明提前,所以当调用表达式在函数表达式前面会报错提示sayAge is not a function ,如果调试表达式在函数表达式后面。就能正常使用。
5. 如下代码的输出?为什么
当在同一个作用域内定义了名字相同的变量和方法的话,无论其顺序如何,变量的赋值会覆盖方法的赋值.
6. 如下代码的输出?为什么
7. 如下代码的输出?为什么?
输出结果是错误,fn不是一个函数
原因:fn被声明并被赋值为1,此时的fn不是一个函数,而console.log(fn(fn))是输出这个fn这个函数,所以发生冲突;
8 .如下代码的输出?为什么?
9. 如下代码的输出?为什么
10. 如下代码的输出?为什么
版权归饥人谷--楠柒所有如有转发请标明出处谢谢