1. 函数声明和函数表达式有什么区别?
函数声明:
形式上 function fuctionName(){//statement};声明了一个名字为functionName的函数,浏览器解析的时候,先要做函数声明前置,在globlecontext的AO中,声明此函数,此时,你在全球作用域下(包括函数声明之前的位置)调用,都可以找到这个函数。函数表达式:
形式上 var someThing=fuction (){//statement};虽然这也是声明了一个函数(匿名的),但实际上浏览器解析的时候,先做的是变量提升,在globlecontext的AO中,声明的是一个变量,假如,在函数声明之前调用该函数,是不能够找到这个函数的,因为调用的时候必然要调用的someThing这个变量,但是变量值在提升变量的时候未给出。
2.什么是变量的声明前置?什么是函数的声明前置
变量的声明前置:
变量的声明前置就是在函数内部,首先要做的事也是类似于浏览器做变量提升,先在当前上下文的AO中声明这个变量。函数的声明前置:
函数的声明前置是,当我们用函数声明来声明一个函数时,函数就会在至当前上下文的AO中声明这个这个函数,同时,在函数内部的上下文的scope中,给声明的函数开辟一个空间,并指向父元素的AO.
3.arguments是什么?
- arguments是一个伪类数组,目前仅仅知道,他是一个函数内部自带的一个类似于数组的参数,我们可以调用arguments[],来获取传入函数内部的参数,并且支持索引,支持length属性。
4.函数的"重载"怎样实现?
- 首先,JS中不同于其他语言,没有重载,例如其他语言中,我们可以设定。但是我们可以控制函数体内部的逻辑语句来实现重载。
例如:
<script language="JavaScript">
function f(length)
{
alert("高为:"+length);
}
function f(length,width)
{
alert("高为:"+length+",宽为:"+width);
}
</srcipt>
/* 上面这个段代码行不通,第一个函数会被第二个覆盖,不能实现 f(10)想要的效果。*/
但是我们可以这么做
<script language="JavaScript">
function f(length)
{
var len= arguments.length;
if(1 == len)
{
var width = arguments[1];
alert("高为:"+length+",宽为:"+width);
}
else
{
alert("高为:"+length);
}
}
</srcipt>
5.立即执行函数表达式是什么?有什么作用?
- 立即执行表达式是什么?
(function (){})();
(function(){}());
上面就是两个常见的立即执行表达式,当我们建立一个匿名函数时,并希望他执行时,我们想到可以这样 function (){}(); 但是实际上,语法上不对,因为浏览器读到这里时,会认为这是一个函数声明,但是没有给出函数名字,所以会报错。但是我们在 function (){}加上括号,意义就不一样了,因为JS中小括号内部是一个表达式,表达式后面加括号,函数可以立即执行的, 和函数表达式声明一样
var something= functiong (){
console.log ( "hello")
}();
所以,我们只需要让浏览器明白,我们前面function (){} 是一个函数表达式就可以了,类似的方法有许多,而已加上各种运算符,让浏览器知道,我们这是一个函数表达式,这就可以了。类似的有很多。
-
为什么要用立即执行函数表达式?
因为JS并没有块级作用域的概念,你在全局或者局部声明的变量 极有可能会被自己或者他人覆盖掉,为了保护这些的变量,我们可以给他加上一层外壳,封装起来,这样,外部变量就不会对内部的变量造成影响了。
求n!,用递归来实现
function doRecursion(n){
if(n<0){
console.log('You input a wrong number');
}
else if(n===0||n===1){
return 1;
}
else if(n>0){
return n*multiply(n-1);
}
}
7.以下代码输出什么?
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('男');
// 倒数第三行调用函数 ,输出 name: 饥人谷,age:2,sex:男;['饥人谷',2,'男‘],name:valley
// 倒数第二行调用函数,输出 name:小谷,age:3;sex:undefined;['小谷',3,];name:valley;
//最后一行调用函数,输出name:男,age:undefined;sex:undefined;['男'];
name:valley;
8.写一个函数,返回参数的平方和?
function sumOfSquares(){
var sum=0;
for (var i=0;i<arguments.length;i++){
sum=sum+arguments[i]*arguments[i];
}
return sum;
}
var result = sumOfSquares(2,3,4);
var result2 = sumOfSquares(1,3);
console.log(result) ;
console.log(result2) ;
9.如下代码的输出?为什么
console.log(a); //undefined,变量提升,有变量a,但是没有值。
var a = 1;
console.log(b);//error ,没有定义这个变量。
10.如下代码的输出?为什么
sayName('world'); //hello,world.
sayAge(10);//报错 。
function sayName(name){
console.log('hello ', name);
}
var sayAge = function(age){
console.log(age);
};
第一个函数能输出是因为,函数声明前置,可以找到globleContext的OA中有这个函数,然后就可以去执行这个函数的上下文。
第二个变量提升,浏览器不知道sayAge(10)是什么意思,如果放在函数表达式后面,浏览器就知道原来这个sayAge()是一个函数表达式,就会执行了。
11.如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10
bar()
function foo() {
console.log(x)
}
function bar(){
var x = 30
foo()
}
第一步:
globleContext{
A0:{
x:10,
function foo(),
bar(),
}
scope:null;
}
foo().[[scope]]=globleContext.AO
bar().[[scope]]=globleContext.AO
第二步:
执行bar();
在globloContext.AO中找到了 bar();
调用bar();进入bar()函数的barContext
barContext:{
AO:{
x:30,
}
scope:globleContext.AO
}
barContext.AO中没有找到 foo();然后去scope中找,scope指向globleContext.AO, 找到右foo();调用foo();
fooContext:{
AO:{
x:undefined,
}
scope:globleContext.AO
}
执行console.log(x);
但是在AO中没有找到,去scope中找到指向globleContext.AO,找到x的值为10,所以,最终结果就是10。
12.如下代码输出什么? 写出作用域链查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
function foo(){
console.log(x)
}
foo();
}
globleContext: {
AO:{
x:10,
function bar(),
}
scope:null
}
bar.[[scope]]=globleContext.AO;
//第二部;
执行bar(); 在globleContext中找到。
进入bar();
barContext:{
AO:{
x=30;
function foo();
}
scope:globleContext.AO
}
foo.[[scope]]=barContext.AO;
执行 foo();
foo()中没有找到x.去barContext.AO找到了。所以console.log(x);
结果是10。
13. 以下代码输出什么? 写出作用域链的查找过程伪代码
var x = 10;
bar()
function bar(){
var x = 30;
(function (){
console.log(x)
})()
}
1、执行bar(),globleContext中有bar()
2 、进入bar()的上下文;
3、执行立即执行函数表达式,但是函数表达式AO中没有找到X,
4、去scope中找,找到的是barContext.AO中,有x的值,得到30.
14. 以下代码输出什么? 写出作用域链查找过程伪代码
var a = 1;
function fn(){
console.log(a)
var a = 5
console.log(a)
a++
var a
fn3()
fn2()
console.log(a)
function fn2(){
console.log(a)
a = 20
}
}
function fn3(){
console.log(a)
a = 200
}
fn()
console.log(a)
1、执行fn() 在globleContext中找到了,所以,进入fn()的上下文。
2、console.log(a),当前函数的作用域中有a变量,此时没有赋值//输出 **undefined**
3、再次执行console.log(a),上一行,a已经赋值,所以//输出 **5**
4、a++ ; a=6,不用输出。
5、var a, a仍然等于6.
6、执行fn3() ,当前函数的AO中没有,找到globleContext.AO,有fn3(),进入fn3()的上下文中。
7、console.log(a),当前的AO还没有a,所以,去找到上一级的AO,找到globleContext.AO,然后,得到结果// **1**,顺便,修改了globleContext.AO中的a=200;
8、回到fn(),运行fn2(),找到了fn2(),进入fn2(), console.log(a), 当前AO中没有a,找到上一级也就是fn的AO中,a=6 ,所以输出 ** 6 ** ,顺便修改了fnContext中的AO,是20 。
9、执行fn()中的console.log(a),此时受到第8步骤的影响,所以,输出是**20.**
10 、fn()运行结束,此时,再次运行console.log,受到第7 的影响,a变为了200.所以输出**200**