第 1 题
立即执行函数表达式是什么?有什么作用?
1. 立即执行函数是什么
立即执行函数就是
- 声明一个匿名函数
-
马上调用这个匿名函数
上面是一个典型的立即执行函数。
- 首先声明一个匿名函数 function(){alert('我是匿名函数')}。
- 然后在匿名函数后面接一对括号 (),调用这个匿名函数。
那么为什么还要用另一对括号把匿名函数包起来呢?
其实是为了兼容 JS 的语法。
如果我们不加另一对括号,直接写成
function(){alert('我是匿名函数')}()
浏览器会报语法错误。想要通过浏览器的语法检查,必须加点小东西,比如下面几种
(function(){alert('我是匿名函数')} ()) // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) () //用括号把函数包起来
!function(){alert('我是匿名函数')}() // 求反,我们不在意值是多少,只想通过语法检查。
+function(){alert('我是匿名函数')}()
-function(){alert('我是匿名函数')}()
~function(){alert('我是匿名函数')}()
void function(){alert('我是匿名函数')}()
new function(){alert('我是匿名函数')}()
2. 立即执行函数有什么用?
只有一个作用:创建一个独立的作用域。
这个作用域里面的变量,外面访问不到(即避免「变量污染」)。
以一个著名的面试题为例:
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
liList[i].onclick = function(){
alert(i) // 为什么 alert 出来的总是 6,而不是 0、1、2、3、4、5
}
}
为什么 alert 的总是 6 呢,因为 i 是贯穿整个作用域的,而不是给每个 li 分配了一个 i,如下:
那么怎么解决这个问题呢?用立即执行函数给每个 li 创造一个独立作用域即可(当然还有其他办法):
var liList = ul.getElementsByTagName('li')
for(var i=0; i<6; i++){
!function(ii){
liList[ii].onclick = function(){
alert(ii) // 0、1、2、3、4、5
}
}(i)
}
在立即执行函数执行的时候,i 的值被赋值给 ii,此后 ii 的值一直不变。
i 的值从 0 变化到 5,对应 6 个立即执行函数,这 6 个立即执行函数里面的 ii 「分别」是 0、1、2、3、4、5。
第 2 题
求n!,用递归来实现。
function Recursion(n){
if (n>1) return n*Recursion(n-1);
return 1;
}
var a=Recursion(6);
console.log(a);
第 3 题
以下代码输出什么?
function getInfo(name, age, sex){
console.log('name:',name);
console.log('age:', age);
console.log('sex:', sex);
console.log(arguments);
arguments[0] = 'valley';
console.log('name', name);
}
getInfo('饥人谷', 2, '男');
getInfo('小谷', 3);
getInfo('男');
//getInfo('饥人谷', 2, '男');
name:饥人谷
age:2
sex: sex
['饥人谷', 2, '男']
name valley
//getInfo('小谷', 3);
name:小谷
age:3
sex:undefined
['小谷', 3]
name valley
//getInfo('男');
name:男
age:undefined
sex:undefined
['男']
name valley
第 4 题
写一个函数,返回参数的平方和?
function sumOfSquares(){
}
var result = sumOfSquares(2,3,4)
var result2 = sumOfSquares(1,3)
console.log(result) //29
console.log(result2) //10
function sumOfSquares(){
var sum = 0;
for (var i=0;i
第 5 题
如下代码的输出?为什么?
console.log(a);
var a = 1;
console.log(b);
undefined
error
var a声明提前
等价于
var a;
console.log(a);
a= 1;
console.log(b);
console.log(a)中的a声明未赋值,所以返回undefined
console,log(b)中的b在全局作用域中遍寻不到所需变量,所以抛出异常 ReferenceError
第 6 题
如下代码的输出?为什么?
sayName('world');
sayAge(10);
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
hello world
error
- 函数声明提前,函数表达式无法声明提前,var sayAge
等价于
function sayName(name){
console.log('hello ', name);
}
var sayAge;
sayName('world');
sayAge(10);
sayAge= function(age){
console.log(age);
};
- sayName('world')查看sayName前面有函数声明,所以为hello world
- sayAge(10)查看sayName前面有var sayAge声明,说明sayAge()被分配给所在作用域,因此sayAge()不会返回ReferenceError。但是sayAge此时没有赋值,sayAge()由于对undefined值进行函数调用而导致非法操作,因此抛出异常TypeError
第 7 题
写一个函数squireArr,其参数是一个数组,作用是把数组中的每一项变为原值的平方
var arr = [3, 4, 6]
function squireArr( arr ){
//补全
}
squireArr(arr)
console.log(arr) // [9, 16, 36]
var arr = [3, 4, 6];
function squireArr( arr ){
for(var i=0;i
第 8 题
如下代码的输出?为什么?
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
10
函数声明提前
等价于
var x=10
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
bar()
- bar()在该作用域找bar声明,找到了,进去,
- 进入到bar作用域里,foo()在该作用域找不到函数声明,于是往上一层找,找到了,在foo()作用域中,console.log(x)的x在foo()下的作用域里找不到变量x,于是继续往上一层作用域找,找到了,所以x的值等于10,console.log(x)本身值等于undefined
第 9 题
写一个函数squireArr,其参数是一个数组,返回一个新的数组,新数组中的每一项是原数组对应值的平方,原数组不变
var arr = [3, 4, 6]
function squireArr( arr ){
//补全
}
var arr2 = squireArr(arr)
console.log(arr) // [3, 4, 6]
console.log(arr2) // [9, 16, 36]
var arr = [3, 4, 6];
function squireArr( arr ){
var arr2 = [];
for (var i = 0;i < arr.length;i++)
arr2[i] = arr[i] * arr[i];
return arr2;
}
var arr2 = squireArr(arr);
console.log(arr); // [3, 4, 6]
console.log(arr2); // [9, 16, 36]
第 10 题
如下代码的输出?为什么?
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
30
等价于
var x=10
function bar() {
var x=30
function foo(){
console.log(x)
}
foo()
}
bar()
第 11 题
如下代码的输出?为什么?
var a = 1
function fn1(){
function fn2(){
console.log(a)
}
function fn3(){
var a = 4
fn2()
}
var a = 2
return fn3
}
var fn = fn1()
fn() //输出多少
2
fn()在该作用域找函数声明,没有,找函数表达式,找到被赋值fn1(),fn1()在该作用域找函数声明,找到,在fn1()作用域下,return fn3,
在fn1()函数作用域找fn3函数声明,找到,在fn3()作用域下,遇到fn2(),在该作用域找fn2(),没找到,从上一级找,找到,在fn2()作用域下,遇到console.log(a),a在该作用域找不到变量声明,往上一级找,找到,var a=2 ,所以最后结果为2
第 13 题
如下代码的输出?为什么?
var a = 1
function fn1(){
function fn3(){
function fn2(){
console.log(a)
}
fn2()
var a = 4
}
var a = 2
return fn3
}
var fn = fn1()
fn() //输出多少
undefined
注意 var a=4 变量声明提前 var a 提前 在fn2()前面,所以为undefined
第 14 题
如下代码的输出?为什么?
var obj1 = {a:1, b:2};
var obj2 = {a:1, b:2};
console.log(obj1 == obj2);
console.log(obj1 = obj2);
console.log(obj1 == obj2);
false
{a:1, b:2}
true
- obj1和obj2的指针地址不同,打印false;
- 将obj2指针地址赋值给obj1,并打印对象;
- 由于obj1和obj2的指针地址相同,打印true。
第 15 题
如下代码的输出?为什么?
var a = 1
var c = { name: 'jirengu', age: 2 }
function f1(n){
++n
}
function f2(obj){
++obj.age
}
f1(a)
f2(c)
f1(c.age)
console.log(a)
console.log(c)
1;object{name: "jirengu",age: 3}
原因:a的值传递给n,n的内存和a的内存不是一个地址,所以n自增后不改变a,同样执行f1(c.age)时也不改变c.age。而对象作为参数时,传递的是地址值,f(2)执行的语句改变了该地址下的内容,使age自增1。所以f2(c)执行结束后改变了c.age由2变为了3。