JavaScript 面向对象之四:作用域链

参数及返回值

形参和实参

// 函数内部是一个封闭的环境,可以通过参数的方式,把外部的值传递给函数内部
// 带参数的函数声明
function 函数名(形参1, 形参2, 形参...){
    // 函数体
}

// 带参数的函数调用
函数名(实参1, 实参2, 实参3);

解释:

  1. 形式参数:在声明一个函数的时候,为了函数的功能更加灵活,有些值是固定不了的,对于这些固定不了的值。我们可以给函数设置参数。这个参数没有具体的值,仅仅起到一个占位置的作用,我们通常称之为形式参数,也叫形参。
  2. 实际参数:如果函数在声明时,设置了形参,那么在函数调用的时候就需要传入对应的参数,我们把传入的参数叫做实际参数,也叫实参。

function fn(a, b) {
    console.log(a + b);
}
var x = 5, y = 6;
fn(x,y); 
// x,y 实参,有具体的值。函数执行的时候会把x,y复制一份给函数内部的a和b。
// 函数内部的值是复制的新值,无法修改外部的x,y
var f = function (one) {
    console.log(one);
}
f(1, 2, 3)

由于 JavaScript 允许函数有不定数目的参数,所以需要一种机制,可以在函数体内部读取所有参数。

arguments对象 — 函数的实参参数集合

var f = function (one) {
    console.log(arguments);
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
}
f(1, 2, 3)

rest参数

由于JavaScript函数允许接收任意个参数,于是我们就不得不用arguments来获取所有参数:

// 只获取出a,b意外的参数
function foo(a, b) {
    var i, datas = [];
    if (arguments.length > 2) {
        for (i = 2; i<arguments.length; i++) {
            datas.push(arguments[i]);
        }
    }
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(datas);
}
foo(1,2,3,4,5);

为了获取 除了 已定义参数ab之外的参数,我们不得不循环arguments,并且循环要从索引2开始以便排除前两个参数,这种写法很别扭,只是为了获得额外的datas参数,有没有更好的方法?

ES6标准引入了rest参数,上面的函数可以改写为:

function foo(a, b, ...rest) {
    console.log('a = ' + a);
    console.log('b = ' + b);
    console.log(rest);
}

foo(1, 2, 3, 4, 5);
// 结果:
// a = 1
// b = 2
// Array [ 3, 4, 5 ]


foo(1);
// 结果:
// a = 1
// b = undefined
// Array []

rest参数只能写在最后,前面用...标识,从运行结果可知,传入的参数先绑定ab,多余的参数以数组形式交给变量rest,所以,不再需要arguments我们就获取了全部参数。

如果传入的参数连正常定义的参数都没填满,也不要紧,rest参数会接收一个空数组(注意不是undefined)。

注意因为rest参数是ES6新标准,所以,请使用新型浏览器;

返回值

当函数执行完的时候,并不是所有时候都要把结果打印。我们期望函数给我一些反馈(比如计算的结果返回进行后续的运算),这个时候可以让函数返回一些东西。也就是返回值。函数通过return返回一个返回值

//声明一个带返回值的函数
function 函数名(形参1, 形参2, 形参...){
  //函数体
  return 返回值;
}

//可以通过变量来接收这个返回值
var 变量 = 函数名(实参1, 实参2, 实参3);

函数的调用结果就是返回值,因此我们可以直接对函数调用结果进行操作。

返回值详解
如果函数没有显示的使用 return语句 ,那么这个函数就没有任何返回值,仅仅是执行了而已;
如果函数使用 return语句,那么跟在return后面的值,就成了函数的返回值;
如果函数使用 return语句,但是return后面没有任何值,那么函数的返回值也是:undefined ,

函数使用 return 语句后,这个函数会在执行完 return 语句之后停止并立即退出,也就是说 return 后面的所有其他代码都不会再执行。

  • return 后没有任何内容,可以当做调试来使用;

递归

执行代码,查看执行结果:

function fn1 () {
    console.log(111);
    fn2();
    console.log('fn1');
}

function fn2 () {
    console.log(222);
    fn3();
    console.log('fn2');
}

function fn3 () {
    console.log(333);
    fn4();
    console.log('fn3');
}

function fn4 () {
    console.log(444);
    console.log('fn4');
}

fn1()
/*
** 执行结果为: 
111
222
333
444
fn4
fn3
fn2
fn1
*/

最简单的一句话介绍递归:函数内部自己调用自己

递归案例:

计算 1+2+3+……+100 的结果

function sum(n){
    if(n>1){
        return n + sum(n-1);
    }else{
        return 1; 
    }
}
var jieguo = sum(5);
console.log(jieguo);

递归必须要有判断条件,不加判断会死循环;

作用域

作用域(scope)指的是变量存在的范围。在 ES5 的规范中,Javascript 只有两种作用域:一种是全局作用域,变量在整个程序中一直存在,所有地方都可以读取;另一种是函数作用域(局部作用域),变量只在函数内部。

函数外部声明的变量就是全局变量(global variable),它可以在函数内部读取。

var v = 1;

function f() {
    console.log(v);
}

f();
// 1

在函数内部定义的变量,外部无法读取,称为“局部变量”(local variable)。

function f(){
    var v = 1;
}

v // ReferenceError: v is not defined

注意,对于var命令来说,局部变量只能在函数内部声明,在其他区块中声明,一律都是全局变量。

作用域链

只有函数可以制造作用域结构, 那么只要是代码,就至少有一个作用域, 即全局作用域。凡是代码中有函数,那么这个函数就构成另一个作用域。如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域。

将这样的所有的作用域列出来,可以有一个结构: 函数内指向函数外的链式结构。就称作作用域链。

function f1() {
    var num = 123;
    function f2() {
        console.log( num );
    }
    f2();
}
var num = 456;
f1();

函数内部的变量声明的提升

与全局作用域一样,函数作用域内部也会产生“变量提升”现象。

var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部。

function foo() {
    console.log(y);//undefined
    var y = 'Bob';
} 
foo();

注意: JavaScript引擎自动提升了变量y的声明,但不会提升变量y的赋值。

对于上述foo()函数,JavaScript引擎看到的代码相当于:

function foo() {
    var y; // 提升变量y的申明 
    var x = 'Hello, ' + y; 
    alert(x);
    y = 'Bob';
}

函数本身的作用域

var a = 1;
var x = function () {
    console.log(a);
};
function f() {
    var a = 2;
    x();
}
f(); // 1 
// 讨论结果为什么是 1  ?

函数本身也是一个值,也有自己的作用域。
它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。
总之,函数执行时所在的作用域,是定义时的作用域,而不是调用时所在的作用域。

var x = function () {
    console.log(a);
};
function y(f) {
    var a = 2;
    f(); 
}
y(x);// ReferenceError: a is not defined
function foo() {
    var x = 1;
    function bar() {
        console.log(x);
    }
    return bar; 
}
var x = 2;
var f = foo();
f(); // 1

猜你喜欢

转载自blog.csdn.net/github_27314097/article/details/81841987
今日推荐