函数的扩展

2018-01-18  本文已影响0人  falcon_li

1.函数参数的默认值;

function log(x, y = 'World') {

    console.log(x, y);

}

log('Hello') // Hello World

log('Hello', 'China') // Hello China

log('Hello', '') // Hello

1.1参数变量是默认声明的,所以不能用let或const再次声明。

function foo(x = 5) {

    let x = 1; // error

    const x = 2; // error

}

1.2 参数名不能重复

1.3 默认参数的位置

一般为函数的尾参数;

如果非尾部的参数设置默认值,实际上这个参数是没法省略的。省略则会报错

2.函数的 length 属性;

指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。也就是说,指定了默认值后,length属性将失真。

3.作用域(暂时不能完全理解

3.1 一旦设置了参数的默认值,函数进行声明初始化时,参数会形成一个单独的作用域(context)。等到初始化结束,这个作用域就会消失。这种语法行为,在不设置参数默认值时,是不会出现的。

4. 应用

4.1 throwIfMissing 函数

function throwIfMissing() {

    throw new Error('Missing parameter');

}

function foo(mustBeProvided = throwIfMissing()) {

    return mustBeProvided;

}

foo() // Error: Missing parameter

4.2 rest 参数

ES6 引入 rest 参数(形式为...变量名),用于获取函数的多余参数,这样就不需要使用arguments对象了。rest 参数搭配的变量是一个数组,该变量将多余的参数放入数组中。

注意,rest 参数之后不能再有其他参数(即只能是最后一个参数),否则会报错。

函数的 length 属性,不包括 rest 

5. 严格模式(不太理解)

从 ES5 开始,函数内部可以设定为严格模式。从 ES5 开始,函数内部可以设定为严格模式。

ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。

6. name 属性

函数的 name 属性,返回函数的函数名

6.1 对于匿名函数

var f = function () {};

// ES5 f.name // ""

// ES6 f.name // "f"

6.2 Function构造函数返回的函数实例,

name属性的值为anonymous

(new Function).name // "anonymous"

bind返回的函数,name属性值会加上bound前缀。

function foo() {};

foo.bind({}).name // "bound foo"

(function(){}).bind({}).name // "bound "

7.箭头函数

7.1 基本用法

ES6 允许使用箭头( => )定义函数

var f = v => v;

上面函数等价于

var f = function(v) { return v; };

如果箭头函数不需要参数或者需要多个参数,就用圆括号()代表参数部分

var f = () => 5;

// 等同于

var f = function () { return 5 };

var sum = (num1, num2) => num1 + num2;

//等同于

var sum = function(num1,num2){

    return num1+num2;

}

如果代码块部分多于一条语句,就要用大括号将它们包裹起来,用 return 语句返回;

var sum = (sum1+sum2)=>{return num1+ num2 ;}

由于大括号被解释为一个代码块,所以如果箭头函数返回一个对象,必须用括号将对象括起来,否则会报错;

// 报错

let getTempItem = id => { id: id, name: "Temp" };

// 不报错

let getTempItem = id => ({ id: id, name: "Temp" });

如果箭头函数只有一条语句,并且没有返回值,则可以使用以下语句

let fn=() => void doesNotReturn();

箭头函数可以结合变量解构使用

const foo = ({first,last})=>first+' '+last;

//等同于

function foo(person){

    return person.first + ' ' person.last;

}

箭头函数使表达更加简洁

const a = n => n % 2 == 0 ;

const b = n => n * n ;

箭头函数的一个主要作用是简化回调函数

例1一个参数

//正常回调函数

[1,2,3].map( function(x ){

                                        return x * })

//箭头函数

[1,2,3].map(x => x * x);

例2 多个参数

//    正常函数

const a = value.sort(function(x,y){

                                                    return x+ y;

                                                         });

// 箭头函数

const b = value.sort((x,y)=> x+y);

例3 rest 参数

const numbers = (...nums) => nums;

number(1,2,3,4,5);

// [1,2,3,4,5]

const a = (x,...y)=>[x,y];

a(1,2,3,4,5);

// [1,[2,3,4,5]]

7.2 注意事项

(1) 函数内的 this 对象,是定义时所在的对象,而不是使用时所在的对象;

(2)不可以当作构造函数,不能使用 new 对象,否则会报错;

(3)不可以使用 arguments 对象,若果要使用,则使用 rest参数 代替;

(4)不可以使用 yield 命令,所以箭头函数不可用作 Generator 函数;

this 对象的指向是可变的,但是在箭头函数中,它是固定的;

7.3 嵌套的箭头函数(难点,理解不了)

箭头函数中还可以嵌套箭头函数

例1 ES5 的嵌套函数

function insert(value) {

    return {into: function (array) {

                   return {after: function (afterValue) {                                                                                                 array.splice(array.indexOf(afterValue) + 1, 0, value);

                                return array;

                                                                            }

                                };

                                                    }

                };

}

insert(2).into([1, 3]).after(1); //[1, 2, 3]

//等同于

let insert = (value) => ({into: (array) => ({after: (afterValue) => {                                                                  array.splice(array.indexOf(afterValue) + 1, 0, value);

                            return array; }}                

                                                                )}

                                    );

insert(2).into([1, 3]).after(1); //[1, 2, 3]

下面是一个部署管道机制(pipeline)的例子,即前一个函数的输出是后一个函数的输入。(暂时不懂)

const pipeline = (...funcs) => val => funcs.reduce((a, b) => b(a), val);

const plus1 = a => a + 1;

const mult2 = a => a * 2;

const addThenMult = pipeline(plus1, mult2);

addThenMult(5) // 12

8.双冒号运算符

箭头函数可以绑定this对象,大大减少了显式绑定this对象的写法(call、apply、bind)。但是,箭头函数并不适用于所有场合,所以现在有一个提案,提出了“函数绑定”(function bind)运算符,用来取代call、apply、bind调用

函数绑定运算符是并排的两个冒号(::),双冒号左边是一个对象,右边是一个函数;该运算符会自动将左边的对象,作为上下文环境(即this对象),绑定到右边的函数上面。

foo::bar;

// 等同于 bar.bind(foo);

foo::bar(...arguments);

// 等同于 bar.apply(foo, arguments);

const hasOwnProperty = Object.prototype.hasOwnProperty;

function hasOwn(obj, key) { return obj::hasOwnProperty(key); }


如果双冒号左边为空,右边是一个对象的方法,则等于将该方法绑定在该对象上面。

var method = obj::obj.foo;

// 等同于 var method = ::obj.foo;

let log = ::console.log;

// 等同于 var log = console.log.bind(console);

双冒号运算符的运算结果,还是一个函数,因此可以采用链式写法

// 例一

import { map, takeWhile, forEach } from "iterlib";

getPlayers()

::map(x => x.character())

::takeWhile(x => x.strength > 100)

::forEach(x => console.log(x));

// 例二

let { find, html } = jake;

document.querySelectorAll("div.myClass") ::find("p") ::html("hahaha");

9.尾调用优化

什么是尾调用?

尾调用(Tail Call)是函数式编程的一个重要概念,本身非常简单,一句话就能说清楚,就是指某个函数的最后一步是调用另一个函数。

上一篇 下一篇

猜你喜欢

热点阅读