ES6学习(二):函数的扩展

chapter07 函数的扩展

7.1 函数默认值

7.1.1 参数默认值简介

传统做法的弊端(||):如果传入的参数相等于(==)false的话,仍会被设为默认值,需要多加入一个if判断,比较麻烦。

参数变量是默认声明的,不可在函数体内部重复声明。

参数的默认值会在每次调用的时候重新计算

7.1.2 和解构赋值默认值结合使用

用两个例子来说明

  • Example1

    function foo({x, y=5}) {
      console.log(x, y);
    }
    
    foo({})         // undefined, 5
    foo({x:1})      // 1, 5
    foo({x:1, y:2}) // 1, 2
    foo()           // TypeError: Cannot read   property 'x' of undefined
  • Example2
    function m1({x = 0, y = 0} = {}) {
        return [x, y];
    }
    
    function m2({x, y} = {x: 0, y: 0}) {
        return [x, y];
    }
    
    m1()              // [0, 0]
    m2()              // [0, 0]
    
    m1({x: 3, y: 8})  // [3, 8]
    m2({x: 3, y: 8})  // [3, 8]
    
    m1({x: 3})        // [3, 0]
    m2({x: 3})        // [3, undefined]
    
    m1({})            // [0, 0]
    m2({})            // [undefined, undefined]
    
    m1({z: 3})        // [0, 0]
    m2({z: 3})        // [undefined, undefined]

7.1.3 参数默认值的位置

设置了默认值的参数应当在参数列表的末尾(同其他编程语言相同)

7.1.4 函数的length属性

返回没有指定默认值的参数的个数

说明:

rest参数不会被计入到length属性
如果设置了默认值得参数并不是尾参数(这样是不对滴),那么从这个设置了默认值得参数开始后面的参数都不会被计入到length属性之中。

7.2 rest参数

参考java的rest参数 ...rest rest成为了一个数组,可以用来代替arguments
rest参数之后不能有其他参数,否则报错

7.3 严格模式

ES5函数内部可以设定为严格模式

ES6规定如果函数使用了默认值、结构赋值或者扩展运算符的话,就不可以在函数体内部使用严格模式(‘use strict‘)

这是因为函数在执行的时候会先执行函数参数,再执行函数体。但是从函数体才可以知道参数是否应该以严格模式执行,但是参数却已经先于函数体执行。

规避方法:

  • 设定全局的严格模式
  • 讲函数包裹在一个无参的立即执行函数内部

7.4 函数的name属性

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

  • 如果一个匿名函数被赋值给一个变量

    • ES5的name属性会返回空字符串
    • ES6的name属性会返回真正的函数名称
  • 如果一个具名函数被赋值给一个变量
    • ES5和ES6均会返回具名函数声明时的名称
  • Function构造函数返回的函数实例,name属性值返回anonymous
  • bind返回的函数,name属性值之前会加上bound前缀

7.5 箭头函数

7.5.1 基本用法

var f = v => v
等价于
var f = function(v) {
    return f;
}

var f = () => 5;
等价于
var f = function() {
    return 5;
}

var (num1, num2) => num1 + num2
等价于
var (num1, num2) => {return num1 + num2;}
等价于
var sum = function (num1, num2) {
    return num1 + num2;
}

var getTempItem = id => ({id: id, name: 'Temp'});

const full = ({first, last}) => last + " " + last;

7.5.2 箭头函数的注意事项

  1. 箭头函数没有this,在箭头函数的内部使用this的话,这个this指向的是箭头函数声明时所在的对象
  2. 不可以用箭头函数当构造器(因为箭头函数是没有this的)
  3. 不可以使用arguments对象,该对象在箭头函数函数体内部不存在。如果想使用的话,就用rest参数
  4. 不可以使用yield命令,因此不可以用作Generator函数
  5. arguments、super和new.target变量在箭头函数的内部都是不存在的
  6. 由于箭头函数的内部不存在this,故call()、apply()和bind()函数都是不可用的。

7.6 绑定this

函数绑定运算符 ::

::的左边是一个对象

::的右边是一个函数

该运算符会自动讲左边的对象作为上下文环境

由于该运算符返回的还是原对象,所以可以链式调用

7.7 尾调用优化

7.7.1 尾调用优化概念

某个函数的最后一步是调用另一个函数

以下情况不属于尾调用

function f(x) {
    let y = g(x);
    return y;
}
//还有赋值操作

function f(x) {
    return g(x) + 1;
}
//调用之后还有操作

function f(x) {
    g(x)
}
// 实质为return undefined

7.7.2 尾调用优化

尾调用由于是函数的最后一步操作,所以不需要保存外层函数的调用栈,可以节省内存,这就是尾调用优化的意义。

只有不再用到外层函数的内部变量,内部函数的调用帧才会取代外层函数的调用帧,否则无法进行尾调用优化

7.7.3 尾递归

我调我自己

阶乘的尾递归实例

function factorial(n, total) {
    if (n === 1) return total;
    return factorial(n - 1, n * total)
}

factorial(5, 1)    // 120

斐波那契数列的尾递归实例

// 非尾递归
function Fibonacci(n) {
    if (n <= 1) return 1;
    return Fibonacci(n - 1) + Fibonacci(n - 2);
}

// 尾递归优化
function Fibonacci(n, ac1 = 1, ac2 = 2) {
    if (n <= 1) return ac2;
    return Fibonacci(n - 1, ac2, ac2 + 1)
}

7.7.4 实现尾递归

尾递归的实现在于改线原有函数使得保证最后一步仅仅调用自己。

实质是讲调用的内部函数所需要用到的外部函数的局部变量作为参
数传递给内部函数,从而切断内部函数对外部函数的调用。

实现方法有以下几种:

  • 在尾递归函数之外提供一个正常形式的函数
  • 使用函数式编程中的柯里化,讲多参数的函数转换为单参数的函数
  • 使用ES6的函数参数默认值
function factorial(n, total = 1) {
    if (n === 1) return total;
    return factorial(n-1, n*total);
}
factorial(5)    // 120

递归本质上是一种循环操作,纯粹的函数式编程语言没有循环操作命令,所有的循环都是使用递归实现的。在支持尾调用优化的语言,循环可以使用递归代替,而且递归最好使用尾递归。

7.7.5 严格模式

ES6的尾调用优化只会在严格模式之下开启,正常模式之下是无效的。

原因是,正常模式之下,函数内部有两个变量func.arguments和func.caller,分别返回函数调用时的参数和调用者。严格模式下会禁用这两个变量。

7.7.6 尾递归优化的实现

在不支持尾递归优化的环境中,应该自己尝试实现尾调用优化。方法例如蹦床函数等。

原则是:使用循环调用递归。具体来说,就是把递归函数的每一步改写成返回一个函数,下面是一个例子。

function sum(x, y)  {
    if (y > 0) return sum(x + 1, y - 1);
    else return x;
}

// 优化之后

function sum(x, y) {
    if (y > 0) {
        return sum.bind(null, x + 1, y - 1);
    } else {
        return x;
    }
}

7.7.8 函数参数的尾逗号

和C语言里的参数的,一致

原文地址:https://www.cnblogs.com/JGC-HUST/p/10523925.html

时间: 2024-10-12 07:31:45

ES6学习(二):函数的扩展的相关文章

ES6 入门系列 - 函数的扩展

1函数参数的默认值 基本用法 在ES6之前,不能直接为函数的参数指定默认值,只能采用变通的方法. function log(x, y) { y = y || 'World'; console.log(x, y); } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello World 上面代码检查函数log的参数y有没有赋值,如果没有,则指定默认值为World.这种写法的

ES6系列四 函数的扩展

一丶ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面. function log(x, y = 'World') { console.log(x, y); } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello 二丶与解构赋值结合 function fetch(url, { body = '', method = 'GET', headers = {} }

ES6小实验-函数的扩展

函数参数默认值 ES6允许为函数的参数直接设置默认值,即直接写在参数定义的后面 function log (x, y = "world") { console.log(x, y) } log("Hello")//Hello world 上面代码中,y是默认声明的,参数默认值可以与解构赋值的默认值,结合使用 function log ({x, y = "world"}) { console.log(x, y) } log({x: "Hel

ES6学习之函数扩展

函数默认参数 function test(x = 1, y = 2) { return x + y } test(5, 6) //11 test() //3 若默认参数在必须参数之前,要想取得默认参数,只有当传入的值为undefined才能取到 function test(x = 1, y) { console.log(x,y) } test(5, 6) //5,6 test(1) //3 undefined test(null,1) //null 1 test(undefined,1) //1

JavaScript学习笔记--ES6学习(五) 数值的扩展

ES6 对于数值类型 (Number) 进行了一下扩展: 1.对于二进制和八进制提供了新的写法 ES6对于二进制和八进制的数值提供了新的写法,分别用0b (或者0B) 和0o (或者0o) 表示.例如: 0b111110111 === 503 // true 0o767 === 503 //true 由于从ES5开始,严格模式中,八进制不再允许使用前缀0来表示,因此在ES6中进一步明确,要用0o来表示. 如果要将0b和0o前缀的字符串数值转换为十进制,要使用Number方法, 例如: var i

ES6学习--箭头函数

1. 箭头函数基本形式 let func = (num) => num; let func = () => num; let sum = (num1,num2) => num1 + num2; [1,2,3].map(x => x * x); 2. 箭头函数基本特点 (1). 箭头函数this为父作用域的this,不是调用时的this 箭头函数的this永远指向其父作用域,任何方法都改变不了,包括call,apply,bind.普通函数的this指向调用它的那个对象. let pe

JavaScript学习笔记 -- ES6学习(二) let 和const

ES6 中新增了两个命令: let 和const. let命令: let 用于声明变量,和var 类似,但是所声明的变量只在代码块中有效,不存在变量提升,有暂时性死区. 1.只在代码块中有效 和var 命令不同的是,let 声明的变量只在代码块中有效,例如 { let a = 1; var b = 2; } console.log(b); // print 2; console.log(a); // this will cause error. 2. 不存在变量提升 所谓变量提升,就是在同一作用

ES6 - Note3:数组、对象与函数的扩展

一.数组的扩展,ES6在数组扩展了一些API,以实现更多的功能 1.Array.from:可以将类数组和可遍历的数据结构转换成真正的数组,如下所示 var a = { '0':1,'1':1,length:2 }; var arr = Array.from(a); console.log(arr) Array [ 1, 1 ] ---------------ES5的实现----------- var arr = [].slice.call(a); console.log(arr) Array [

ES6学习及总结(二):对象的解构

ES6学习及总结(二):对象的解构 一:数组的解构 1:ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring).本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值. let [foo, [[bar], baz]] = [1, [[2], 3]]; foo // 1 bar // 2 baz // 3 let [ , , third] = ["foo", "bar", "