ES6 逐点突破系列 -- 函数的扩展

}

f() // 1

var x = 1;

function foo(x, y = function() { x = 2; }) {

var x = 3;

y();

console.log(x);

}

foo() // 3

x // 1

上面代码中,函数foo的参数形成一个单独作用域。这个作用域里面,首先声明了变量x,然后声明了变量y,y的默认值是一个匿名函数。这个匿名函数内部的变量x,指向同一个作用域的第一个参数x。函数foo内部又声明了一个内部变量x,该变量与第一个参数x由于不是同一个作用域,所以不是同一个变量,因此执行y后,内部变量x和外部全局变量x的值都没变。

如果将var x = 3的var去除,函数foo的内部变量x就指向第一个参数x,与匿名函数内部的x是一致的,所以最后输出的就是2,而外层的全局变量x依然不受影响。

var x = 1;

function foo(x, y = function() { x = 2; }) {

x = 3;

y();

console.log(x);

}

foo() // 2

x // 1

P.S. 下面代码中,参数x = x形成一个单独作用域。实际执行的是let x = x,由于暂时性死区的原因,这行代码会报错”x 未定义“。

var x = 1;

function foo(x = x) {

// …

}

foo() // ReferenceError: x is not defined

2. reset参数


arguments对象不是数组,而是一个类似数组的对象。所以为了使用数组的方法,必须使用Array.prototype.slice.call先将其转为数组。rest 参数就不存在这个问题,它就是一个真正的数组,数组特有的方法都可以使用。

函数的length属性,不包括 rest 参数。

(function(a) {}).length // 1

(function(…a) {}).length // 0

(function(a, …b) {}).length // 1

P.S. rest 参数之后不能再有其他参数(即只能是最后一个参数)

3. 严格模式


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

4. name属性


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

需要注意的是,ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。

var f = function () {};

// ES5

f.name // “”

// ES6

f.name // “f”

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

function foo() {};

foo.bind({}).name // “bound foo”

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

5. 箭头函数


注意点

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

function foo() {

return () => {

return () => {

return () => {

console.log(‘id:’, this.id);

};

};

};

}

var f = foo.call({id: 1});

var t1 = f.call({id: 2})()(); // id: 1

var t2 = f().call({id: 3})(); // id: 1

var t3 = f()().call({id: 4}); // id: 1

上面代码之中,只有一个this,就是函数foo的this,所以t1、t2、t3都输出同样的结果。因为所有的内层函数都是箭头函数,都没有自己的this,它们的this其实都是最外层foo函数的this。

除了this,以下三个变量在箭头函数之中也是不存在的,指向外层函数的对应变量:arguments、super、new.target。

由于箭头函数没有自己的this,所以当然也就不能用call()、apply()、bind()这些方法去改变this的指向。

(2)不可以当作构造函数,也就是说,不可以使用new命令,否则会抛出一个错误。

(3)不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。

(4)不可以使用yield命令,因此箭头函数不能用作 Generator 函数。

6. 尾调用优化


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

function f(x){

return g(x);

}

函数调用会在内存形成一个“调用记录”,又称“调用帧”(call frame),保存调用位置和内部变量等信息。如果在函数A的内部调用函数B,那么在A的调用帧上方,还会形成一个B的调用帧。等到B运行结束,将结果返回到A,B的调用帧才会消失。如果函数B内部还调用函数C,那就还有一个C的调用帧,以此类推。所有的调用帧,就形成一个“调用栈”(call stack)。

尾调用由于是函数的最后一步操作,所以不需要保留外层函数的调用帧,因为调用位置、内部变量等信息都不会再用到了,只要直接用内层函数的调用帧,取代外层函数的调用帧就可以了。

尾递归

function Fibonacci (n) {

if ( n <= 1 ) {return 1};

return Fibonacci(n - 1) + Fibonacci(n - 2);

}

Fibonacci(10) // 89

Fibonacci(100) // 超时

Fibonacci(500) // 超时

function Fibonacci2 (n , ac1 = 1 , ac2 = 1) {

if( n <= 1 ) {return ac2};

return Fibonacci2 (n - 1, ac2, ac1 + ac2);

}

Fibonacci2(100) // 573147844013817200000

Fibonacci2(1000) // 7.0330367711422765e+208

Fibonacci2(10000) // Infinity

改写递归函数

两个方法可以解决这个问题。方法一是在尾递归函数之外,再提供一个正常形式的函数。

function tailFactorial(n, total) {

if (n === 1) return total;

return tailFactorial(n - 1, n * total);

}

function factorial(n) {

return tailFactorial(n, 1);

}

factorial(5) // 120

函数柯里化

function currying(fn, n) {

return function (m) {

return fn.call(this, m, n);

};

}

function tailFactorial(n, total) {

if (n === 1) return total;

return tailFactorial(n - 1, n * total);

}

const factorial = currying(tailFactorial, 1);

factorial(5) // 120

第二种方法就简单多了,就是采用 ES6 的函数默认值。

function factorial(n, total = 1) {

if (n === 1) return total;

return factorial(n - 1, n * total);

}

factorial(5) // 120

严格模式

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

这是因为在正常模式下,函数内部有两个变量,可以跟踪函数的调用栈。

func.arguments:返回调用时函数的参数。

func.caller:返回调用当前函数的那个函数。

尾调用优化发生时,函数的调用栈会改写,因此上面两个变量就会失真。严格模式禁用这两个变量,所以尾调用模式仅在严格模式下生效。

function restricted() {

‘use strict’;

restricted.caller; // 报错

restricted.arguments; // 报错

}

restricted();

尾递归优化的实现

function tco(f) {

var value;

var active = false;

var accumulated = [];

return function accumulator() {

accumulated.push(arguments);

总结

阿里十分注重你对源码的理解,对你所学,所用东西的理解,对项目的理解。

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

最新阿里蚂蚁金服四面(已拿offer)Java技术面经总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/34150.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

晨持绪科技:开好一家抖音小店运营怎么做

在数字时代&#xff0c;抖音小店以其独特的社交媒体优势迅速崛起&#xff0c;成为许多创业者的新宠。但如何有效运营&#xff0c;却是一门学问。首要任务是确定你的小店定位&#xff0c;这关系到后续的产品选择、目标客户群及营销策略。定位明确后&#xff0c;接下来便是挑选适…

泡泡玛特携手浦东美术馆 推出SKULLPANDA重磅联名

6月20日&#xff0c;泡泡玛特“SKULLPANDA入画”快闪店在上海浦东美术馆重磅开幕&#xff0c;现场SKULLPANDA x 浦东美术馆联名吊卡“SKULLPANDA入画”重磅上线&#xff0c;这是潮流艺术家熊喵首次和国内顶级美术馆联动合作&#xff0c;除了吊卡以外&#xff0c;现场还有系列衍…

IP地址SSL证书快速申请攻略

一、IP地址定义 互联网协议地址&#xff08;IP地址&#xff09;是为互联网上的每台设备分配的一个唯一标识符。它就像是设备在网络中的“家庭住址”&#xff0c;使得数据包能够准确地发送到目的地。IP地址有两种主要类型&#xff1a;IPv4和IPv6。IPv4使用32位地址&#xff0c;…

简单使用百度地图

官方文档 <!DOCTYPE html> <html> <head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><meta name="viewport" content

执行shell脚本出现 $‘ \r‘ 符号导致执行失败【解决】

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

深信服AC行为管理报错

报错信息&#xff1a; e0:alarmevent.cpp:54 exec cmd: /ac/common/app/kvupd -v failed 说明&#xff1a; 截止到上网行为管理12.0.80及全网行为管理13.0.102版本&#xff0c;AC凌晨&#xff08;0点-7点&#xff09;会重启进程让设备更好的运行&#xff0c;凌晨重启告警属于正…

android 彩虹进度条自定义view实现

实现一个彩虹色进度条功能&#xff0c;不说明具体用途大家应该能猜到。想找别人造的轮子&#xff0c;但是没有合适的&#xff0c;所以决定自己实现一个。 相关知识 android 自定义view LinearGradient 线性渐变 实现步骤 自定义view 自定义一个TmcView类继承View 重写两…

SpringBoot系列之搭建WebSocket应用

SpringBoot系列之@ServerEndpoint方式开发WebSocket应用。在实时的数据推送方面,经常会使用WebSocket或者MQTT来实现,WebSocket是一种不错的方案,只需要建立连接,服务端和客户端就可以进行双向的数据通信。很多网站的客户聊天,也经常使用WebSocket技术来实现。 WebSocket…

Mac角色扮演游戏推荐:仙剑奇侠传四 for Mac 安装包

《仙剑奇侠传四》拥有精美的画面、优秀的音乐和丰富的剧情内容&#xff0c;成为了仙剑系列中的经典作品之一。游戏在发行后获得了极高的口碑和销量&#xff0c;成为了仙剑系列中的经典之作。在游戏中&#xff0c;玩家将扮演不同的角色&#xff0c;进行冒险探索、与各种敌人战斗…

# bash: chkconfig: command not found 解决方法

bash: chkconfig: command not found 解决方法 一、chkconfig 错误描述&#xff1a; 这个错误表明在 Bash 环境下&#xff0c;尝试执行 chkconfig 命令&#xff0c;但是系统找不到这个命令。chkconfig 命令是一个用于管理 Linux 系统中服务的启动和停止的工具&#xff0c;通常…

2024 年网站分析必备:Fullstory、APILayer 及 Openinstall API 服务

在当今数字化的时代&#xff0c;网站和应用的成功运营离不开对用户行为和网站性能的深入洞察。2024 年的今天&#xff0c;随着技术的不断发展&#xff0c;各种先进的 API 服务应运而生&#xff0c;为我们提供了强大的工具来优化用户体验、保障网站可用性以及提升 App 推广效果。…

Linux编译器 gcc/g++

gcc/g的简介 GCC&#xff08;英文全拼&#xff1a;GNU Compiler Collection&#xff09;是 GNU 工具链的主要组成部分&#xff0c;是一套以 GPL 和 LGPL 许可证发布的程序语言编译器自由软件&#xff0c;由 Richard Stallman 于 1985 年开始开发。gcc是GCC中的C语言编译器&…

爱迪特两年创业板上市路:销售费用率远高同行,侵权风险引关注

《港湾商业观察》施子夫 王璐 从2022年4月7日就冲刺创业板的爱迪特&#xff08;秦皇岛&#xff09;科技股份有限公司&#xff08;以下简称&#xff0c;爱迪特&#xff09;&#xff0c;预计将很快登陆资本市场。 爱迪特日前披露中签结果&#xff1a;本次发行股份数量为约1902…

关于最强模型Claude 3.5 Sonnet,你需要知道的10条总结!

大家好,我是木易,一个持续关注AI领域的互联网技术产品经理,国内Top2本科,美国Top10 CS研究生,MBA。我坚信AI是普通人变强的“外挂”,所以创建了“AI信息Gap”这个公众号,专注于分享AI全维度知识,包括但不限于AI科普,AI工具测评,AI效率提升,AI行业洞察。关注我,AI之…

Python自动化(8)——pyqt5界面

Python自动化(8)——pyqt5界面 注意&#xff1a;pyqt5的界面使用时必须有app QApplication(sys.argv)这行代码&#xff0c;否则会出现错误并且无法显示窗口&#xff1a;QWidget: Must construct a QApplication before a QWidget 一些基础的控件 QMainWindow QMainWindow是…

【经验分享】免费版虚拟机VMware Workstation Pro 17下载方式

【经验分享】免费版虚拟机VMware Workstation Pro 17下载方式 前言一、免费虚拟机下载方式二、 安装过程总结 前言 我真的是服了&#xff0c;现在的CSDN时效性为什么这么差了。都快一个月了还没有博主更新个人免费版虚拟机VMware Workstation Pro&#xff0c;甚至很多人还不知…

RFID技术在汽车轮胎加工工艺中的革新应用

RFID技术在汽车轮胎加工工艺中的革新应用 物联网技术的飞速发展&#xff0c;无线射频识别&#xff08;Radio Frequency Identification&#xff0c;简称RFID&#xff09;技术因其独特的优势&#xff0c;在各行各业中展现出巨大的应用潜力。特别是在汽车制造业&#xff0c;RFID…

推荐一款好用的浏览器翻译插件——欧路翻译

近些年&#xff0c;机器翻译的效果越来越好&#xff0c;于是也有更多的开发者&#xff0c;开发了免费使用的浏览器翻译插件。这大大的帮助了我们查看国外的网站&#xff0c;有利于大家获取更多的信息。 在此&#xff0c;给大家推荐一款免费好用的浏览器插件——欧路翻译。支持…

我在高职教STM32——LCD液晶显示(4)

大家好&#xff0c;我是老耿&#xff0c;高职青椒一枚&#xff0c;一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次&#xff0c;同行应该都懂的&#xff0c;老师在课堂上教学几乎是没什么成就感的。正因如此&#xff0c;才有了借助 CSDN 平台寻求认同感和成就…

[经验] 如何做虾炒白菜 #学习方法#知识分享

如何做虾炒白菜 虾炒白菜的做法 虾炒白菜是一道营养丰富且美味可口的菜肴&#xff0c;虾肉的鲜嫩与白菜的甜脆相结合&#xff0c;口感极佳。接下来&#xff0c;让我们一起来学习一下虾炒白菜的详细做法。 食材准备 虾&#xff1a;约200克&#xff08;选用新鲜活虾&#xff…