函数与作用域

2017-07-04  本文已影响0人  饥人谷_Young丶K

函数声明和函数表达式有什么区别?

函数声明:function functionName() {}
函数表达式:var fn = function() {}

函数声明不必放到调用的前面,函数表达式声明必须放到调用的前面。

什么是变量的声明前置?什么是函数的声明前置

在一个作用域下,var 声明的变量和function 声明的函数会前置.前置到当前作用域的开头。
变量声明的前置:

console.log(i);
var i = 1;     //undefined

代码执行过程:

var i;.   //提前在程序最开始,声明一个变量i 未赋值 所以是 undefined
console.log(i);
i = 1;   //console.log(i)在 i = 1 ;赋值语句之前,而变量声明前置所以打印的时候i是undefined;

函数的声明前置:

test(1)
function test(x){
  console.log(x);
}     // 1

通过函数声明的方式建立的函数表达式会提前,这段代码过程:

function test(x){};
test(1)

输出的结果为1;因为function test(x){} 整个函数 已经提前到了test(1)之前。
但是,同样的方法,使用函数表达式,其出现的结果是报错,因为其调用在其声明之前。
如下例子:

func1();    // 输出:我是函数声明

func2();    // 报错 

console.log(a); // 输出:undefined

function func1() {
    console.log("我是函数声明");
}

var func2 = function() {
    console.log("我是函数表达式");
}

var a = 10;

arguments 是什么?

arguments是一个类数组对象。代表传给一个function的参数列表。
 arguments对象是函数内部的本地变量;arguments 已经不再是函数的属性了。可以在函数内部通过使用 arguments 对象来获取函数的所有参数。这个对象为传递给函数的每个参数建立一个条目,条目的索引号从0开始。它包括了函所要调用的参数。object对象。类数组。

函数的"重载"怎样实现?

首先,要明确,在JS中,没有重载。同名函数会覆盖。但可以在函数体针对不同的参数调用执行相应的逻辑。
如下例:

function printPeopleInfo(name, age, sex){
    if(name){
      console.log(name);
    }

    if(age){
      console.log(age);
    }

    if(sex){
      console.log(sex);
    }
  }
  printPeopleInfo('Byron', 26);//Byron 26
  printPeopleInfo('Byron', 26, 'male');//Byron 26 male

javascript不能支持函数的重载,如下:

function f(length) 
{ 
   alert("高为:"+length); 
} 

function f(length,width) 
{ 
   alert("高为:"+length+",宽为:"+width); 
}

上面那段代码其实是行不通的,因为函数定义时的参数个数和函数调用时的参数个数没有任何关系。在函数中可以用f.arguments[0]和f.arguments[1]得到调用时传入的第一和第二个参数,所以定义function(length),后面用f(10,10)调用是没有问题的。所以在上面这段代码中,第二个函数是永远不可能被调用到的,那么,要怎样才能实现像函数重载那样的功能呢?
那就是在函数定义中用f.arguments.length判断一下调用时传入的参数个数。然后对不同的情况采用不同的处理方式。 如下:

function f() 
{ 
    var len= arguments.length; 
    if(2 == len) 
    { 
        var length = arguments[0]; 
        var width = arguments[1]; 
        f2(length,width); 
    } 
    else 
    { 
        var length = arguments[0]; 
        f1(length); 
    } 
} 

function f1(length) 
{ 
    alert("高为:"+length); 
} 

function f2(length,width) 
{ 
    alert("高为:"+length+",宽为:"+width); 
}

*这样,你就可以给函数f()传入一个参数也可以传入两个参数了,比如f(10)和f(10,10); *

function f(length) 
{ 
    var len= arguments.length; 
    if(1 == len) 
    { 
        var width = arguments[1]; 
        alert("高为:"+length+",宽为:"+width); 
    } 
    else 
    { 
        alert("高为:"+length); 
    } 
}

立即执行函数表达式是什么?有什么作用

(function(){
    var a = 1;
})()

作用: 隔离作用域。
  JavaScript有很多致命缺陷,比如JavaScript中没有命名空间,而且只有function代码块内部可以隔离变量作用域,自调用匿名函数就用来防止变量弥散到全局,以免各种js库冲突。

求n!,用递归来实现

function fn(n) {
                if(n < 0){
                alert("error")
                }
        else if(n == 0 || n == 1)  {
            return 1;
        }
        return n * fn(n-1);
    }
    fn(5);

以下代码输出什么?

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:2
sex: undefined
['小谷','3']
name valley

name:男
age:undefined
sex:undefined
['男']
name valley

写一个函数,返回参数的平方和?

 function sumOfSquares(){
    var sum = 0;
    for (var i = 0; i < arguments.length; i++) {
        sum += arguments[i]*arguments[i]
          }
          return sum;
    }
   var result = sumOfSquares(2,3,4)
   var result2 = sumOfSquares(1,3)
   console.log(result)  //29
   console.log(result2)  //10

如下代码的输出?为什么

console.log(a);
var a = 1;
console.log(b);
//  undefined 
//  ReferenceError: b is not defined

console.log(a)输出的是undefined、因为变量在当前作用域下被前置,结果在console.log(a)前面的var a;虽然声明了但是没有赋值,结果为undefined.
console.log(b) b完全是没有声明也没有赋值,结果是报错.//ReferenceError: b is not defined
*/

如下代码的输出?为什么

    sayName('world');
    sayAge(10);
    function sayName(name){
        console.log('hello ', name);
    }
    var sayAge = function(age){
        console.log(age);
    };
// hello world
// TypeError: sayAge is not a function

sayNme('world');会返回'hello world'.
sayAge(10);因为是使用表达式定义,所以,当调用在定义之前就会报错,sayAge is not a function.

如下代码输出什么? 写出作用域链查找过程伪代码

var x = 10
bar() 
function foo() {
  console.log(x)
}
function bar(){
  var x = 30
  foo()
}
/*   10
1.
globalContext = {
  AO: {
    x: 10, foo: function, bar: function
  },

foo.[[scope]] = globalContext.AO
bar.[[scope]] = globalContext.AO
}
2.调用bar()
barContext = {
  AO: {
    x: 30
  }
  Scope: bar.[[scope]] = globalContext.AO
}
3.调用foo()
fooContext = {
  AO: {}
  Scope: foo.[[scope]] = globalContext.AO
} */

如下代码输出什么? 写出作用域链查找过程伪代码

var x = 10;
bar() 
function bar(){
  var x = 30;
  function foo(){
    console.log(x) 
  }
  foo();
}   
输出: 30
1. 
globalContext={
  AO:{
    x:10, 
    bar : function
  },
  Scope:null
}
  bar.[[scope]]=globalContext.AO
2. 调用bar
barContext={
  AO:{
    x: 30,
    foo:function
  },
Scope: bar.[[scope]]=globalContext.AO
}
foo.[[scope]]=barContext.AO
3. 调用foo
fooContext={
  AO:{},
  Scope: foo.[[scope]]=barContext.AO
}

以下代码输出什么? 写出作用域链的查找过程伪代码

var x = 10;
bar() 
function bar(){
  var x = 30;
  (function (){
    console.log(x)
  })()
}
输出: 30
1.
globalContext={
  AO:{
    x: 10,
    bar:function
 }
    Scope: null
}
bar.[[scope]]=globalContext.AO
2.调用bar
barContext={
  AO:{
    x:30, 
    function(){}
  }
Scope:bar.[[scope]]=globalContext.AO
}
function().[[scope]]=barContext.AO
3. 调用function()
functionContext={
  AO:{}
  Scope:function().[[scope]]=barContext.AO
}

以下代码输出什么? 写出作用域链查找过程伪代码

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)
输出: undefined 5 1 6 20 200
1.
globalContext={
  AO:{
    a:200,
    fn:function,
    fn3:function
  }
Scope: null
}
fn.[[scope]]=globalContext.AO
fn3.[[scope]]=globalContext.AO
2. 调用fn
fnContext={
  AO:{
  a:20, 
  fn2:function  
}
Scope: fn.[[scope]]=globalContext.AO
}
fn2.[[scope]]=fnContext.AO
3. 调用fn3
fn3Context={
  AO:{}
  Scope:fn3.[[scope]]=globalContext.AO
}
4. 调用fn2
fn2Context={
  AO:{}
 Scope:fn2.[[scope]]=fnContext.AO
}

上一篇 下一篇

猜你喜欢

热点阅读