函数

函数语法

1. 定义函数

function 自定函数名(参数) { ... }

function abs(x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

上述abs()函数的定义如下:

  • function指出这是一个函数定义;
  • abs是函数的名称;
  • (x)括号内列出函数的参数,多个参数以,分隔;
  • { ... }之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。

 

请注意,函数体内部的语句在执行时,一旦执行到return时,函数就执行完毕,并将结果返回。因此,函数内部通过条件判断和循环可以实现非常复杂的逻辑。

如果没有return语句,函数执行完毕后也会返回结果,只是结果为undefined

2.匿名函数定义

function (x) { ... }

区别在于匿名函数没有函数名

var abs = function (x) {
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
};

函数调用

调用函数时,按顺序传入参数即可:

abs(10); // 返回10
abs(-9); // 返回9

当函数需要参数而没有传递参数时,要避免收到undefined,可以对参数进行检查:

function abs(x) {
    if (typeof x !== 'number') {
        throw 'Not a number';
    }
    if (x >= 0) {
        return x;
    } else {
        return -x;
    }
}

关键字arguments

只在函数内部起作用,并且永远指向当前函数的调用者传入的所有参数。arguments类似Array但它不是一个Array

arguments
function foo(x) {
    console.log('x = ' + x); // 10
    for (var i=0; i<arguments.length; i++) {
        console.log('arg ' + i + ' = ' + arguments[i]); // 10, 20, 30
    }
}
foo(10, 20, 30);
// x = 10
// arg 0 = 10
// arg 1 = 20
// arg 2 = 30


// 利用arguments,你可以获得调用者传入的所有参数。也就是说,即使函数不定义任何参数,还是可以拿到参数的值:
function abs() {
    if (arguments.length === 0) {
        return 0;
    }
    var x = arguments[0];
    return x >= 0 ? x : -x;
}

abs(); // 0
abs(10); // 10
abs(-9); // 9

// 实际上arguments最常用于判断传入参数的个数。你可能会看到这样的写法:
// foo(a[, b], c)
// 接收2~3个参数,b是可选参数,如果只传2个参数,b默认为null:
function foo(a, b, c) {
    if (arguments.length === 2) {
        // 实际拿到的参数是a和b,c为undefined
        c = b; // 把b赋给c
        b = null; // b变为默认值
    }
    // ...
}

rest参数

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

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)。

变量作用域

1. 不同函数内部的同名变量互相独立,互不影响:

function foo() {
    var x = 1;
    x = x + 1;
}

function bar() {
    var x = 'A';
    x = x + 'B';
}

2. 从内向外寻找,需要的变量内部没有向外部寻找,内部有将屏蔽外部函数的变量

function foo() {
    var x = 1;
    function bar() {
        var x = 'A';
        console.log('x in bar() = ' + x); // 'A'
    }
    console.log('x in foo() = ' + x); // 1
    bar();
}

foo();

// x in foo() = 1
// x in bar() = A

3. 为了减少命名冲突,可以把代码全部放入唯一的名字空间中。如:

// 唯一的全局变量MYAPP:
var MYAPP = {};

// 其他变量:
MYAPP.name = 'myapp';
MYAPP.version = 1.0;

// 其他函数:
MYAPP.foo = function () {
    return 'foo';
};

局部变量

为了解决块级作用域,ES6引入了新的关键字let,用let替代var可以申明一个块级作用域的变量:

function foo() {
    var sum = 0;
    for (let i=0; i<100; i++) {
        sum += i;
    }
    // SyntaxError:
    i += 1;
}

常量

ES6标准引入了新的关键字const来定义常量,constlet都具有块级作用域:

const PI = 3.14;
PI = 3; // 某些浏览器不报错,但是无效果!
PI; // 3.14

解构赋值

赋值
// 现在,在ES6中,可以使用解构赋值,直接对多个变量同时赋值:
var array = ['hello', 'JavaScript', 'ES6'];
var x = array[0];
var y = array[1];
var z = array[2];

/* 现在,在ES6中,可以使用解构赋值,直接对多个变量同时赋值:*/
var [x, y, z] = ['hello', 'JavaScript', 'ES6'];

/* 如果数组本身还有嵌套,
也可以通过下面的形式进行解构赋值,
注意嵌套层次和位置要保持一致:*/
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'

/* 解构赋值还可以忽略某些元素:*/
let [x, [y, z]] = ['hello', ['JavaScript', 'ES6']];
x; // 'hello'
y; // 'JavaScript'
z; // 'ES6'

/* 如果需要从一个对象中取出若干属性,
也可以使用解构赋值,
便于快速获取对象的指定属性:*/
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school'
};
var {name, age, passport} = person; //name = 小明, age = 20, passport = G-12345678

/* 对一个对象进行解构赋值时,
同样可以直接对嵌套的对象属性进行赋值,
只要保证对应的层次是一致的:*/
var person = {
    name: '小明',
    age: 20,
    gender: 'male',
    passport: 'G-12345678',
    school: 'No.4 middle school',
    address: {
        city: 'Beijing',
        street: 'No.1 Road',
        zipcode: '100001'
    }
};
var {name, address: {city, zip}} = person;
name; // '小明'
city; // 'Beijing'
zip; // undefined, 因为属性名是zipcode而不是zip
// 注意: address不是变量,而是为了让city和zip获得嵌套的address对象的属性:
address; // Uncaught ReferenceError: address is not defined

方法

在一个对象中绑定函数,称为这个对象的方法。

方法
var xiaoming = {
    name: '小明',
    birth: 1990
};

// 给xiaoming绑定一个函数age()根据系统时间计算出年龄自动更新
var xiaoming = {
    name: '小明',
    birth: 1990,
    age: function () {
        var y = new Date().getFullYear();
        return y - this.birth;
    }
};

xiaoming.age; // function xiaoming.age()
xiaoming.age(); // 今年调用是25,明年调用就变成26了

/* 关键字this this是一个特殊变量,
它始终指向当前对象,也就是xiaoming这个变量。
所以,this.birth可以拿到xiaoming的birth属性。*/
function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};
xiaoming.age(); // 25, 正常结果
getAge(); // NaN

apply()可以控制this的指向

function getAge() {
    var y = new Date().getFullYear();
    return y - this.birth;
}

var xiaoming = {
    name: '小明',
    birth: 1990,
    age: getAge
};

xiaoming.age(); // 25
getAge.apply(xiaoming, []); // 25, this指向xiaoming, 参数为空

要指定函数的this指向哪个对象,可以用函数本身的apply方法,它接收两个参数,第一个参数就是需要绑定的this变量,第二个参数是Array,表示函数本身的参数。

另一个与apply()类似的方法是call(),唯一区别是:

  • apply()把参数打包成Array再传入;

  • call()把参数按顺序传入。

比如调用Math.max(3, 5, 4),分别用apply()call()实现如下:

Math.max.apply(null, [3, 5, 4]); // 5
Math.max.call(null, 3, 5, 4); // 5

对普通函数调用,我们通常把this绑定为null

高阶函数

function add(x, y, f) {
    return f(x) + f(y);
}

var x = add(-5, 6, Math.abs); // 11
console.log(x); // 11

1. Array.map(function)

var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
arr.map(String); // ['1', '2', '3', '4', '5', '6', '7', '8', '9']

function pow(x) {
    return x * x;
}
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
var results = arr.map(pow); // [1, 4, 9, 16, 25, 36, 49, 64, 81]
console.log(results); //1,4,9,16,25,36,49,64,81

2.  reduce

再看reduce的用法。Array的reduce()把一个函数作用在这个Array[x1, x2, x3...]上,这个函数必须接收两个参数,reduce()把结果继续和序列的下一个元素做累积计算,其效果就是:

[x1, x2, x3, x4].reduce(f) = f(f(f(x1, x2), x3), x4)

比方说对一个Array求和,就可以用reduce实现:

var arr = [1, 3, 5, 7, 9];
arr.reduce(function (x, y) {
    return x + y;
}); // 25
版权声明:本文为墨宝工作室原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/sxzmobao/p/16410756.html