Skip to main content

moregeek program

ES6学习 第七章 函数的扩展-多极客编程

前言


本章介绍函数的扩展。有些不常用的知识了解即可。
本章原文链接:函数的扩展


函数参数的默认值


ES6 允许为函数的参数设置默认值,即直接写在参数定义的后面。
当函数形参没有被赋值时,才会将默认值赋值给函数参数。


// 默认值直接写在行参后面
function sampleFn(sample = 0, sample1 = 0) {
return sample + sample1;
}

注意:


  • 参数变量是默认声明的,所以不能用letconst再次声明。
  • 使用参数默认值时,函数不能有同名参数。
  • 参数默认值是惰性求值的。
  • 函数的默认值指定后,函数length属性返回的是没有指定默认值的参数的个数。
  • 参数的默认值一旦设定,函数进行声明初始化时,参数会形成一个单独的作用域(context)。
// 默认值直接写在行参后面
function sampleFn(sample = 0, sample1 = 0,sample = 1) { // 不能有同名参数

let sample = 1; // 不能再次声明

return sample + sample1;
}


注意:通常情况下,定义了默认值的参数,应该是函数的尾参数。也就是放在最后面。



解构赋值默认值


// 函数的默认值与结构赋值的默认值可以结合使用
function sampleFn({ sample = 0, sample1 = 0 } = {}) { // 函数参数默认值
return sample + sample1;
}

console.log(sampleFn({ sample: 23, sample1: 33 })); // 56 参数需对应解构赋值的类型

作用域


当函数参数设置了默认值,函数进行声明初始化时,函数参数会生成一个单独的作用域,等到初始化结束,该作用域就会消失。而且该行为只在函数参数指定了默认值才会出现。


let sample = 1;

/*
在声明的时候出现单独作用域
在这个作用域中,变量没有定义,于是指向外层变量
函数调用时,函数内部变量影响不到默认值变量
*/
function sampleFn(sample1 = sample) {
let sample = 2;
console.log(sample1);
return sample1;
}

sampleFn() // 1

rest 参数


ES6 引入 rest 参数 ,用于获取函数的多余参数。
arguments 对象是类数组,rest 参数是真正的数组。

形式为:...变量名,函数的最后一个命名参数以...为前缀。


// 下面例子中 ...values 为 rest参数 ,用于获取多余参数
const sample = function (title, ...values) {
let sample = values.filter(
(item) => {
return item % 2 === 0;
}
)

return (title + sample);
}

console.log(sample("求偶数", 1, 2, 6, 2, 1)); // 求偶数 2, 6, 2


注意:rest参数 只能是函数的最后一个参数,函数的length不包括rest参数



严格模式


在JavaScript中,只要在函数中的严格模式,会作用于函数参数和函数体。
ES2016 规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。


function sample() { // 参数使用默认值、解构赋值、扩展运算符 
'use strict'; // 开启严格模式
}

name 属性


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


function sample() { };
let sample1 = function () { };
function sample2() {};

console.log(sample.name); // sample
console.log(sample1.name); // sample1

// bound sample2 使用了 bind 方法,输出会有bound前缀
console.log(sample2.bind({}).name);
console.log((new Function).name); // anonymous 构造函数的name值为 anonymous

箭头函数


简单介绍


ES 6 新增一种函数定义方法,使用箭头连接参数列与函数题。
箭头函数相当于匿名函数,并且简化了函数定义,箭头函数没有prototype


// 普通函数
let sample = function (item) {
return item;
};

// 上面函数等同于下面函数

// 使用箭头函数
let sample = (item) => { return item}; // 箭头函数

箭头函数简写


没错,箭头函数还可以简写


  1. 当参数只有一个时,可以省略箭头左边的括号,但没有参数时,括号不可以省略。
  2. 当函数体只有一个表达式时,可省略箭头右边的大括号,但同时必须省略return语句 并写在一行。
  3. 当函数体分多于一条语句,就要使用大括号将它们括起来,并且使用return语句返回。
// 下面几种函数写法都相同
let sample = function (item) {
return item;
};

let sample = (item) => { return item}; // 箭头函数 不省略

let sample = item => { return item}; // 省略左边圆括号

let sample = (item) => item; // 省略右边大括号和 return

let sample = item => item; // ✌省略左边圆括号和右边花括号和return

// 如果不需要返回值的特殊情况
let sample = item => void item;
console.log(sample()); // undefined

注意点


  • 箭头函数 的 This 默认指向定义它的作用域的 This
  • 箭头函数 不能用作构造函数。
  • 箭头函数 不可以使用 arguments 对象,该对象在函数体内不存在。
  • 箭头函数 不可以使用yield命令,也就不能作为 Generator 函数。

箭头函数的this


箭头函数 会继承自己定义时所处的作用域链上一层的this
箭头函数 this在定义的时候已经确定了,所以箭头函数this不会改变。
使用 call()apply() 方法时,也不能重新给箭头函数绑定thisbing()方法无效。


window.sample = "window 内 ";

function sampleFn() {
let thiz = this;
let sample = "sampleFn 内 ";

let sampleObj = {
sample: "sampleObj 内 ",

// 普通函数
sampleFn1: function () {
console.log(thiz === this);
console.log(this.sample);
},

// 箭头函数
sampleFn2: () => {
// 箭头函数的作用域为 sampleObj 上一层为 sampleFn
console.log(thiz === this); //箭头函数的 this
console.log(this.sample);
}
}

sampleObj.sampleFn1(); // false, sampleObj 内
sampleObj.sampleFn2(); // true, window 内
}

sampleFn();

尾调用优化


有两个概念



  1. 尾调用
    尾调用(Tail Call)是函数式编程的一个重要概念,就是指某个函数的最后一步是调用另一个函数。



  2. 尾递归
    函数调用自身,称为递归。如果尾调用自身,就称为尾递归。

ES6 明确规定,所有 ECMAScript 的实现,都必须部署“尾调用优化”。
这就是说,ES6 中只要使用尾递归,就不会发生栈溢出(或者层层递归造成的超时),相对节省内存。


这是什么意思呢?


尾调用的作用,在原文中是这样写的:



我们知道,函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。
尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。



换种方式解释吧



函数被调用的时候会有函数执行上下文被压入执行栈中,直到函数执行结束,对应的执行上下文才会出栈。
在函数A的内部调用函数B,如果函数B中有对函数A中变量的引用,那么函数A即使执行结束对应的执行上下文也无法出栈,如果函数B内部还有调用函数C那么要等函数C执行完,函数A、B对应的执行上下文才能出栈,以此类推,执行栈中要上一个函数(内层函数)的执行上下文,这就是尾调用优化。



// 尾递归
function sampleFn(sample) {
if (sample <= 1) return 1;
return sampleFn(sample - 1) + sample;
}
sampleFn(2);

注意 :


  • 当内层函数没有用到外层函数的内部变量的时候才可以进行尾调用优化。
  • 目前只有 Safari 浏览器支持尾调用优化,Chrome 和 Firefox 都不支持。

ES 6 的小修改


函数参数尾逗号


ES2017 允许函数的最后一个参数有尾逗号(trailing comma)。
这样的规定也使得,函数参数与数组和对象的尾逗号规则,保持一致了。


function sampleFn(
sample1,
sample2,
sample3, // 可以在最后一个参数后面加 逗号 ','
) {}

toString()修改


Function.prototype.toString()
ES2019 对函数实例的toString()方法做出了修改。明确要求返回一模一样的原始代码。
toString()方法返回函数代码本身,ES6前会省略注释和空格。


function sampleFn() {
// 注释
}

let sample = sampleFn.toString();
console.log(sample);
//输出 完全一样的原始代码,包括空格与注释
/*
function sampleFn() {
// 注释
}
*/

catch 修改


ES2019 改变了catch语句后面必须携带参数的要求。允许catch语句省略参数。


try {
// ...
} catch { // 不带参数
// ...
}

©著作权归作者所有:来自51CTO博客作者四冥的原创作品,如需转载,请注明出处,否则将追究法律责任
ES6学习 第七章 函数的扩展
https://blog.51cto.com/u_15437747/4711152

#私藏项目实操分享# iframe 在 SAP 三款产品中的三个应用场景-多极客编程

这是 Jerry 2021 年的第 73 篇文章,也是汪子熙公众号总共第 350 篇原创文章。 iframe 是一项历史悠久的前端技术,能够将另一个 HTML 页面嵌入到当前的宿主页面。每个通过 iframe 被嵌入的 HTML 页面都拥有自己独立的浏览上下文,会话历史记录和 DOM 树。虽然 iframe 如果使用不当,可能会引发性能问题和安全隐患,但是它也有其应用场合,即复用第三方应用页面。因

#私藏项目实操分享# 从一个实际的例子出发,理解什么是 Rxjs 的 defer 函数-多极客编程

我们在开发复杂的 Angular 应用时,经常会使用到 Rxjs 的 defer 函数,例如: 创建一个 Observable,在订阅时调用 Observable 工厂为每个新的 Observer 创建一个 Observable 对象。 该函数接收一个输入参数,类型为一个工厂函数。输出为一个 Observable 对象,一旦被订阅时,其绑定的工厂函数会被调用。 defer 的实质是延迟创建机制,

#私藏项目实操分享# 介绍一款开源电商网站的购物车添加功能的实现-多极客编程

目前电商领域有两款比较出名的开源电商网站解决方案,分别是基于 Angular 开发框架,代号为 Spartacus 的开源项目,以及基于 Vue 的 Vue Storefront. 作为 Spartacus 开源项目的开发成员之一,今天我想通过本文,给大家介绍一下我们平时购物时最常使用到的功能之一,添加产品到购物车的技术实现。 即使没有多少 Angular 开发经验的前端程序员,阅读本文之后,也

ES6学习 第六章 数值的扩展-多极客编程

前言 本章介绍数值的扩展。新增了很多方法,有些不常用的方法了解即可。本章原文链接:数值的扩展 进制表示法 ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。八进制就不再允许使用前缀0表示。0b和0o前缀的字符串数值转为十进制,要使用Number方法。 console.log(Number('0b10')); // 二进制 2 console.log(Num

前端常用正则表达式-多极客编程

整理了前端常用的正则表达式,包括链接,html标签,邮箱,手机号等常用的正则表达式,提前完成任务下班。 本文首发于 ​​前端常用正则表达式​​,转载请注明来源 匹配手机号正则/^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][

#yyds干货盘点#three.js中如何切换相机视角-多极客编程

1. 在3D场景中, 我们有时需要从6个面的正视角去预览物体, 效果如下所示 顶视图 底视图 正视图 后视图 右视图 左视图 2. 我们该如何实现了? 动态计算出每个正视角的位置坐标值 动态改变相机的位置即可 缓动动画使用tween插件实现 3. 核心代码 const arr = [] // 保存各个视角的点数据 let car = null let lookDownAng = 20 // /

#私藏项目实操分享# iframe 在 SAP 三款产品中的三个应用场景-多极客编程

这是 Jerry 2021 年的第 73 篇文章,也是汪子熙公众号总共第 350 篇原创文章。 iframe 是一项历史悠久的前端技术,能够将另一个 HTML 页面嵌入到当前的宿主页面。每个通过 iframe 被嵌入的 HTML 页面都拥有自己独立的浏览上下文,会话历史记录和 DOM 树。虽然 iframe 如果使用不当,可能会引发性能问题和安全隐患,但是它也有其应用场合,即复用第三方应用页面。因

#私藏项目实操分享# 从一个实际的例子出发,理解什么是 Rxjs 的 defer 函数-多极客编程

我们在开发复杂的 Angular 应用时,经常会使用到 Rxjs 的 defer 函数,例如: 创建一个 Observable,在订阅时调用 Observable 工厂为每个新的 Observer 创建一个 Observable 对象。 该函数接收一个输入参数,类型为一个工厂函数。输出为一个 Observable 对象,一旦被订阅时,其绑定的工厂函数会被调用。 defer 的实质是延迟创建机制,

#私藏项目实操分享# 介绍一款开源电商网站的购物车添加功能的实现-多极客编程

目前电商领域有两款比较出名的开源电商网站解决方案,分别是基于 Angular 开发框架,代号为 Spartacus 的开源项目,以及基于 Vue 的 Vue Storefront. 作为 Spartacus 开源项目的开发成员之一,今天我想通过本文,给大家介绍一下我们平时购物时最常使用到的功能之一,添加产品到购物车的技术实现。 即使没有多少 Angular 开发经验的前端程序员,阅读本文之后,也

ES6学习 第六章 数值的扩展-多极客编程

前言 本章介绍数值的扩展。新增了很多方法,有些不常用的方法了解即可。本章原文链接:数值的扩展 进制表示法 ES6 提供了二进制和八进制数值的新的写法,分别用前缀0b(或0B)和0o(或0O)表示。八进制就不再允许使用前缀0表示。0b和0o前缀的字符串数值转为十进制,要使用Number方法。 console.log(Number('0b10')); // 二进制 2 console.log(Num

前端常用正则表达式-多极客编程

整理了前端常用的正则表达式,包括链接,html标签,邮箱,手机号等常用的正则表达式,提前完成任务下班。 本文首发于 ​​前端常用正则表达式​​,转载请注明来源 匹配手机号正则/^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][

Spring认证中国教育管理中心-Spring Data Redis框架教程一-多极客编程

原标题:Spring认证中国教育管理中心-Spring Data Redis框架教程一8.1.文件结构参考文档的这一部分解释了 Spring Data Redis 提供的核心功能。它解释了键值模块的概念和语义以及各种商店命名空间的语法。有关键值存储、Spring 或 Spring Data 示例的介绍,请参阅学习 NoSQL 和键值存储。本文档仅涉及 Spring Data Redis 支持,并假