IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> 第三章 函数(深入理解ES6) -> 正文阅读

[游戏开发]第三章 函数(深入理解ES6)

一、剩余参数

剩余参数( rest parameter )由三个点( … )与一个紧跟着的具名参数指定,它会是包 含传递给函数的其余参数的一个数组

	function pick(object, ...keys) { 
		let result = Object.create(null); 
		
		for (let i = 0, len = keys.length; i < len; i++) { 
			result[keys[i]] = object[keys[i]]; 
		}

		return result; 
	}
	
	let book = {
		title: "Understanding ES6", 
		author: "Nicholas C. Zakas", 
		year: 2015
	}

	let bookData = pick(book, "author", "year");
	
	
	console.log(bookData.author); // "Nicholas C. Zakas" 
	console.log(bookData.year); // 2015
	

剩余参数受到两点限制。一是函数只能有一个剩余参数,并且它必须被放在最后。例如,如 下代码是无法工作的:

	// 语法错误:不能在剩余参数后使用具名参数
	function pick(object, ...keys, last) { 
		let result = Object.create(null); 

		for (let i = 0, len = keys.length; i < len; i++) { 
			result[keys[i]] = object[keys[i]]; 
		}

		return result; 
	}

设计剩余参数是为了替代 ES 中的 arguments 。原先在 ES4 中就移除了 arguments 并添加 了剩余参数,以便允许向函数传入不限数量的参数。尽管 ES4 从未被实施,但这个想法被保 持下来并在 ES6 中被重新引入,虽然 arguments 仍未在语言中被移除。 arguments 对象在函数被调用时反映了传入的参数,与剩余参数能协同工作,就像如下程序 所演示的:

	function checkArgs(...args) { 
		console.log(args.length); 
		console.log(arguments.length); 
		console.log(args[0], arguments[0]); 
		console.log(args[1], arguments[1]); 
	}
	checkArgs("a", "b");

二、箭头函数

ES6 最有意思的一个新部分就是箭头函数( arrow function )。箭头函数正如名称所示那样 使用一个“箭头”( => )来定义,但它的行为在很多重要方面与传统的 JS 函数不同:

  1. 没有 this 、 super 、 arguments ,也没有 new.target 绑定: this 、 super 、 arguments 、以及函数内部的 new.target 的值由所在的、最靠近的非箭头函数来决定
  2. 不能被使用 new 调用: 箭头函数没有 [[Construct]] 方法,因此不能被用为构造函 数,使用 new 调用箭头函数会抛出错误。
  3. 没有原型: 既然不能对箭头函数使用 new ,那么它也不需要原型,也就是没有 prototype 属性。
  4. 不能更改 this : this 的值在函数内部不能被修改,在函数的整个生命周期内其值会 保持不变。
  5. 没有 arguments 对象: 既然箭头函数没有 arguments 绑定,你必须依赖于具名参数或 剩余参数来访问函数的参数。
  6. 不允许重复的具名参数: 箭头函数不允许拥有重复的具名参数,无论是否在严格模式 下;而相对来说,传统函数只有在严格模式下才禁止这种重复。

箭头函数语法

当你想使用更传统的函数体、也就是可能包含多个语句的时候,需要将函数体用一对花括号 进行包裹,并明确定义一个返回值,正如下面这个版本的 sum() :

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

// 有效等价于: 
var sum = function(num1, num2) { 
	return num1 + num2; 
};

花括号被用于表示函数的主体,它在你至今看到的例子中都工作正常。但若箭头函数想要从 函数体内向外返回一个对象字面量,就必须将该字面量包裹在圆括号内,例如:

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

// 有效等价于: 
var getTempItem = function(id) { 
	return { 
		id: id, 
		name: "Temp" 
	}; 
};

三、尾调用优化

在 ES6 中对函数最有趣的改动或许就是一项引擎优化,它改变了尾部调用的系统。尾调用( tail call )指的是调用函数的语句是另一个函数的最后语句,就像这样:

function doSomething() { 
	return doSomethingElse(); // 尾调用 
}

在 ES5 引擎中实现的尾调用,其处理就像其他函数调用一样:一个新的栈帧( stack frame )被创建并推到调用栈之上,用于表示该次函数调用。这意味着之前每个栈帧都被保留在内 存中,当调用栈太大时会出问题。

有何不同?

ES6 在严格模式下力图为特定尾调用减少调用栈的大小(非严格模式的尾调用则保持不 变)。当满足以下条件时,尾调用优化会清除当前栈帧并再次利用它,而不是为尾调用创建 新的栈帧:
1.尾调用不能引用当前栈帧中的变量(意味着该函数不能是闭包);
2. 进行尾调用的函数在尾调用返回结果后不能做额外操作;
3. 尾调用的结果作为当前函数的返回值。

类似的,如果你的函数在尾调用返回结果之后进行了额外操作,那么该函数也无法被优化:

"use strict"; 
function doSomething() { 
	// 未被优化:在返回之后还要执行加法 
	return 1 + doSomethingElse(); 
}

此例在 doSomethingElse() 的结果上对其进行了加 1 操作,而没有直接返回该结果,这已足以关闭优化

无意中关闭优化的另一个常见方式,是将函数调用的结果储存在一个变量上,之后才返回了 结果,就像这样:

"use strict"; 
function doSomething() { 
	// 未被优化:调用并不在尾部 
	var result = doSomethingElse(); 
	return result; 
}
//  是因为 doSomethingElse() 的值并没有立即被返回

如何控制尾调用优化

尾调用优化的主要用例是在递归函数中,而且在其中的优化具有最大效果。考虑以下计算阶 乘的函数:

function factorial(n) { 
	if (n <= 1) { 
		return 1; 
	} else { 
		// 未被优化:在返回之后还要执行乘法 
		return n * factorial(n - 1); 
	} 
}
// 不会被优化,如果 n 是一个大数字,那么调用栈的大小会增长,并且可能导致堆栈溢出。

在重写的 factorial() 函数中,添加了第二个参数 p ,其默认值为 1 。 p 参数保存着前 一次乘法的结果,因此下一次的结果就能在进行函数调用之前被算出。当 n 大于 1 时,会 先进行乘法运算并将其结果作为第二个参数传入 factorial() 。这就允许 ES6 引擎去优化这 个递归调用。

function factorial(n, p = 1) { 
	if (n <= 1) { 
		return 1 * p; 
	} else { 
		let result = n * p; // 被优化 
		return factorial(n - 1, result); 
	} 
}

总结

这章有点难理解,主要是尾调用优化,以保持更小的调用栈、使用更少的内存,并防止堆 栈溢出。当能进行安全优化时,它会由引擎自动应用。不过你可以考虑重写递归函数,以便 能够利用这种优化。
共勉

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 18:15:32  更:2022-04-18 18:19:26 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 15:10:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码