1.函数声明和函数表达式有什么区别 ?
函数声明:
function func(){
console.log(1)
}
函数表达式:(一般匿名函数赋给一个变量)
var tmp = function (){
console.log(1)
};
因此函数声明和函数表达式不同之处在于:
1、js引擎在解析javascript代码时会[函数声明提升],把当前执行环境(作用域)上的函数声明给提到执行环境的前头;而函数表达式则必须是等到js引擎执行到它所在的那行代码,才会从上而下一行一行地解析函数表达式中的代码
2、函数声明之后,只需要 func()即可调用;而函数表达式后面可以加括号作为立即执行函数调用,函数声明则不可以。
3、函数声明是以function关键词开始,如果不是,那么它就是函数表达式。
4、函数声明最后面一般不写分号,而函数表达式有分号。
2.什么是变量的声明前置?什么是函数的声明前置
js引擎的工作方式:先解析代码,获取所有被声明的变量,然后一行一行执行,会把所有的变量的声明语句都被提到代码的头部,这就叫做变量的声明前置。
- 变量的声明前置:
①变量前置就是把变量的声明提前到当前作用域的最前面,但变量的赋值仍然按照原来的顺序执行,如果变量声明但未被赋值,变量会自动赋值为undefined。
var a = 2;
等同于
var a;
a = 2;
- 函数的声明前置:
①函数声明前置和变量的声明前置实质是一样的。函数的声明前置有两种情况,一个是使用函数声明,则整个声明都前置,而且会被前置到变量声明的后面;另一个是使用函数表达式,那么规则和变量的声明前置一样。
fn()
function fn(){
console.log(1)
}//1
等同于
function fn(){ console.log (1) }
fn()
- 函数表达式的声明前置:
fn(1)
var f = function fn(n){
console.log(n)
}
等同于
var f;
fn(1)
f = function fn(n){
console.log(n)
}
//Uncaught ReferenceError: fn is not defined(…)
疑问:写上面这题的函数表达式用具名函数还是匿名函数规范呢?
3.arguments 是什么
- 在函数内部,可以使用arguments对象获取到该函数传入的全部参数,一般简称为[参数列表]
(1).arguments是一个类数组对象,代表传给一个function的参数列表,只在函数内部起作用。arguments的值与函数传入实参有关,与函数定义形参无关。
(2).即使函数声明时不用详细写清楚传入的参数的个数和名称,也能使用arguments获取参数。
(3).arguments是一个伪数组,无真正数组的API(eg:push、pop那些方法)。
(4).arguments.length:指的是实参的长度,不是形参的长度。
(5).arguments是function的隐含属性,它将会把实参显示成一个类组对象。
function fn(a,b,c){
console.log(arguments)
console.log(arguments.length)
}
fn(1,2,3,4)
4.函数的重载怎样实现
①重载是很多面向对象语言实现多态的手段之一,相同名字的函数参数个数不同或者顺序不同都被认为是不同的函数,称为函数重载。
②在JavaScript中没有函数重载的概念,函数通过名字确定唯一性,参数不同也被认为是相同的函数,后面的覆盖前面的。
那是否意味着JS不能通过重载功能来实现一个函数,参数不同功能不同呢?
答:JavaScript可以通过自身的属性去模拟函数重载;可以用arguments来实现函数的重载(关键只要传实参的个数有所不同即可)
5.立即执行函数表达式是什么?有什么作用
立即执行函数表达式(Immediately-Invoked Function Expression)简称IIFE
通俗点解释:平时写语句是无需得出结果,但是表达式是需要求出结果的。所以推测出立即执行函数表达式字面意思是一个为了马上得出结果的函数。
- 立即执行函数表达式是什么?
(1).声明一个匿名函数
(2).马上调用这个匿名函数
(3).声明一个匿名函数function(){} ,然后在匿名函数后面加一对括号() ,调用这个匿名函数
(4).在function前面加!、 +、 — 、()可以起到函数定义后立即执行的效果,加上运算符后,就告诉js引擎这是一个函数表达式,不是函数定义。
典型一:(function(){ alert("我是匿名函数") })()
典型二:(function(){ alert("我是匿名函数") }())
典型三:!function (){ alert("我是匿名函数") }()
典型四:var fn =function(n){console.log(n)}(1) //1
- 立即执行函数表达式有什么作用?
作用:创建一个独立的作用域;这个作用域里面的变量,外面访问不到(即避免[变量污染]);
当同时调用多个JS的情况时,很容易造成因为变量名一致或函数名一致而覆盖其他库的变量;所以才需要采用立即执行函数;
定义的变量都成了立即执行函数的局部变量,以后即使变量名或函数名一样也不被污染,同时形成了一个单独的作用域,可以封装一些外部无法读取的私有变量;
6.什么是函数的作用域链
①作用域:作用域就是变量与函数的可访问范围,作用域控制着变量与函数的可见性和生命周期。
- 全局变量:变量没有在函数内声明或者声明的时候没有带var就是全局变量,拥有全局作用域;
- 局部变量:函数内部声明并且以var修饰的变量就是局部变量,只能在函数体内使用,函数的参数虽然没有使用var但仍然是局部变量。
②注意:JavaScript并没有块级作用域,只有函数作用域:变量在声明它们的函数体及其子函数内是可见的。
③作用域链:
作用域链用来变量查询的,在代码执行查找过程中,变量会在当前作用域中进行寻找,如果找不到,就会往沿着作用域链向上一级进行寻找,一直到全局作用域为止,如果找到便会停止(而不理会上一级是否有同名的变量),如果找不到,就会报错。
④作用域只会逐层向上查找,遵循就近原则,只要查找到就停止了。
代码:
1.以下代码输出什么?
2.写一个函数,返回参数的平方和?
//题目:写一个函数,返回参数的平方和
// function sumOfSquares(){
// }
// sumOfSquares(2,3,4); // 29
// sumOfSquares(1,3); // 10
--------
方法1:
function sumOfSquares(){
var result = 0
for(var i=0; i<arguments.length; i++){
result += arguments[i]*arguments[i]
}
return result
}
console.log( sumOfSquares(2,3,4) ); // 29
console.log( sumOfSquares(1,3) ); // 10
-----------
方法2:
function sumOfSquares(){
var result = 0
for(var i=0; i<arguments.length; i++){
result += arguments[i]*arguments[i]
}
console.log(result)
}
sumOfSquares(2,3,4); // 29
sumOfSquares(1,3); // 10
3.如下代码的输出?为什么
console.log(a);//打印为undefined,定义了但未赋值
var a = 1;
console.log(b);//b is not defined,b没有声明,所以直接报错
4.如下代码的输出?为什么
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
等同于
var sayAge
function sayName(name){ //定义时不看函数体内容
console.log('hello ', name);
}
sayName('world') // 输出:hello world
sayAge(10) //输出:sayAge is a not function ;相当于undefined(10),肯定会报错
sayAge = function(age){
console.log(age);
};
5.如下代码的输出?为什么
function fn(){}
var fn = 3;
console.log(fn);
等同于
var fn; //变量的声明前置
function fn(){}//声明提升,函数声明在变量的后面,函数覆盖变量
fn = 3; //变量的赋值覆盖函数的声明
console,log(fn) //输出3
6,如下代码的输出?为什么
function fn(fn2){
console.log(fn2); //函数fn2
var fn2 = 3;
console.log(fn2); //3
console.log(fn); //外层fn函数
function fn2(){
console.log('fnnn2');
}
}
fn(10);
等同于
function fn(fn2){
var fn2;
//注意:传参数时隐式做了 var fn2 = 10
function fn2(){console.log('fnnn2')}; //函数声明前置覆盖了之前的变量
console.log(fn2);// 输出上面的fn2(){}函数
fn2 = 3;
console.log(fn2); //3
console.log(fn); //输出最外层的fn函数,当前作用域(函数fn内部)中没有这个变量,因此向上一级寻找,找到变量fn被声明为函数
}
fn(10)
分析:
1.当输入 fn(10)的时候,把fn2 直接赋值成了数值10;
2.刚进入函数体内部时,var fn2; 这时候 fn2还是等于10;
3.接着被赋值成数值的fn2,又被声明回函数;
4.这个时候console.log(fn2);,那就输出函数fn2;
5.然后又被赋值成数值3;
6.遇到console.log(fn2);输出3
7.然后遇到console.log(fn),输出函数 fn();
7.如下代码的输出?为什么
var fn = 1;
function fn(fn){
console.log(fn);
}
console.log(fn(fn));
等同于
var fn;
function fn(fn){
console.log(fn)
}
fn = 1;
console.log(fn(fn)); //居然是报错!is not a function
第七题解析:因为当函数和变量声明前置,函数的声明覆盖了变量的声明,最后1赋值给fn,这时候fu类型不是function而是number,这时候console.log(fn(fn)) 转换就变成console.log(1(1)) ,所以console.log(fn(fn)) 就报错。显示fn不是一个函数。
ps:请老师解析下,这题好悬,我是在控制台打出才得知会报错
8.如下代码的输出?为什么
//作用域
console.log(j); //undefined
console.log(i); //undefined
for(var i=0; i<10; i++){
var j = 100;
}
console.log(i); //10
console.log(j); //100
-------
等同于
var i;
var j;
console.log(j);
console.log(i);
i=0;
for(i<10;i++){//只有函数才有作用域,for循环没有作用域,所以里面的变量是全局变量
j = 100
}
console.log(i)
console.log(j)
for循环后i跳出就变成10;循环10次后j被赋值了依然还是100,变量不会随着循环的结束而消失
9.如下代码的输出?为什么
fn();
var i = 10;
var fn = 20;
console.log(i);
function fn(){
console.log(i);
var i = 99;
fn2();
console.log(i);
function fn2(){
i = 100;
}
}
----------
等同于
var i; //变量提升
var fn;
function fn(){ //函数声明提升
var i
function fn2(){ //函数定义但未执行
i = 100
}
console.log(i) //undefined
i = 99
fn2()
console.log(i) //100 fn2函数运行后,本来全局的i=99被fn2的i=100覆盖了
}
fn(); //然后执行函数fn
i = 10; //全局 i 给再次赋值10
fn =20;
console.log(i) // 10
10.如下代码的输出?为什么
var say = 0;
(function say(n){
console.log(n);
if(n<3) return;
say(n-1);
}( 10 ));
console.log(say);
------
等同于
var say;
(function say(n){ //立即执行函数
console.log(n); //输出:10 9 8 7 6 5 4 3 2
if(n<3) return;
say(n-1);
}( 10 ));
say = 0
console.log(say);//输出:0
//变量只在函数作用域内生效,并不会影响到外面的变量。所以最后console.log(say)输出0
分析:
1.声明var say = 0;
2.立即执行函数表达式不会提升的,按位置立即执行;
3.进入函数,实参10赋给形参n,n = 10,首先打出console.log(10) ;
4.判断语句if n<3 return,不满足条件,执行say(n-1);继续输出n,一直递归下去 ;
5.直到n=2的时候,n<3此时返回,结束循环,return为空值的时候,就是return出undefined,函数执行完毕;
6.console.log(say)输出0 ,因为立即执行函数表达式就是创建一个独立的作用域;这个作用域里面的变量,外面是访问不到,所以打出全局定义的变量say;
本文版权归区子铭和饥人谷所有,转载请注明来源。