温故而知新篇之《JavaScript忍者秘籍(第二版)》学习总结(一)——函数篇

哦哈哈

前言

这篇文章的总结和学习的内容,讲从第三章开始的;整本书学习时间大概是一星期的时间,利用零散的时间其实就可以学习完。
基础知识,是需要不断学习和补充的,如果总用不到的知识,我们就会忘记;加上我不是计算机专业的,所以也一直在努力💪弥补。

学习的方式

有句古话,“光说不做假把式”;这样就没意思了。
所以还是要敲代码和自己实践,这都是很重要的。

我挺推荐这个微信读书

因为你可以在闲暇时,用手机翻阅,还有读书朗诵的功能;有的时候,我们在看技术书的时候总是在走神。就可以用app的朗诵功能让你更加集中注意力。
image

一定要敲代码!!!!

一定要自己学会总结;这也很重要。好记性不如烂笔头,就是这个道理。

image

JavaScript忍者秘籍第二版的电子版

是epub的版本;《JavaScript忍者秘籍第二版.epub》;阅读电子版是为了更方便 我在电脑上去操作事例的时候更加容易,直接复制出来,打断点。
如果你需要,那么下面就是文档。
image

链接: https://pan.baidu.com/s/1L30_... 密码: n56j


下面就开始我们今天的总结和概况内容。我标题也说,这是重点内容总结,是方便你快速的记忆和回忆知识点,更好的方式还是系统的阅读一遍。

接下来的有些内容,我会直接引入文章的句子,请见怪不怪。
我会按照目录的顺序进行梳理

第3章 新手的第一堂函数课:定义与参数

对象能做的任何一件事,函数也都能做。

函数也是对象,唯一的特殊之处在于它是可调用的(invokable),即函数会被调用以便执行某项动作。

回调函数

function useless(ninjaCallback) {
 return ninjaCallback();
}
这个函数可能没什么用,但它反映了函数的一种能力,即将函数作为另一个函数的参数,随后通过参数来调用该函数。

存储函数

var store = {
 nextId: 1,  //⇽--- 跟踪下一个要被复制的函数
 cache: {},  //⇽--- 使用一个对象作为缓存,我们可以在其中存储函数
 add: function(fn) { 
   if (!fn.id) {
    fn.id = this.nextId++;
    this.cache[fn.id] = fn;
    return true;
  } 
 }  //⇽--- 仅当函数唯一时,将该函数加入缓存
};
function ninja(){}
assert(store.add(ninja), 
     "Function was safely added.");
assert(!store.add(ninja),
     "But it was only added once.");   //⇽--- 测试上面的代码按预期工作
fn.id将会是,传进来fn的唯一标示;如果在传进来相同的函数时,我们会发现这个id是存在的,就不会添加进来。
相当于修改了这个fn函数属性,添加了一个唯一标示ID;
如果是没有加进来的fn,那么就没有这个ID标示。
fn.id = this.nextId++;

函数定义

JavaScript提供了几种定义函数的方式,可以分为5类。

函数声明

 function myFun(){ return 1;}
每个函数声明以强制性的function开头,其后紧接着强制性的函数名,以及括号和括号内一列以逗号分隔的可选参数名。
函数声明必须具有函数名是因为它们是独立语句。一个函数的基本要求是它应该能够被调用,所以它必须具有一种被引用方式,于是唯一的方式就是通过它的名字

image

函数表达式

var myFun = function (){ return 1;}
JavaScript中的函数是第一类对象,除此以外也就意味着它们可以通过字面量创建,可以赋值给变量和属性,可以作为传递给其他函数的参数或函数的返回值。
注意⚠️:
函数声明和函数表达式除了在代码中的位置不同以外,还有一个`更重要的不同点`是:

* 函数声明来说,函数名是强制性的;
* 函数表达式来说,函数名则完全是可选的。
区分函数声明和函数表达式⚠️
《你不知道的JavaScript(上卷)》中,p27页,是这样写的
区分函数声明和函数表达式最简单的方法是看function关键字出现在声明的位置(不仅仅是一行代码,而是整个声明的位置)。 如果function是声明中第一个词,那么就是函数声明,否则就是函数表达式
立即函数

image
标准函数的调用和函数表达式的立即调用的对比

注意⚠️:加括号的函数表达式

函数表达式被包裹在一对括号内。为什么这样做呢?

其原因是纯语法层面的。JavaScript解析器必须能够轻易区分函数声明和函数表达式之间的区别
如果去掉包裹函数表达式的括号,把立即调用作为一个独立语句function() {}(3),JavaScript开始解析时便会结束,因为这个独立语句以function开头,那么解析器就会认为它在处理一个函数声明。每个函数声明必须有一个名字(然而这里并没有指定名字),所以程序执行到这里会报错为了避免错误,函数表达式要放在括号内,为JavaScript解析器指明它正在处理一个函数表达式而不是语句。
funciton(){33}

image

会直接报错,因为这个函数声明是错误的表现形式。

如果加上括号,或者是一元操作符
image

函数表达式要放在括号内,为JavaScript解析器指明它正在处理一个函数表达式而不是语句。
还有一种相对简单的替代方案(function(){}(33))也能达到相同目标(然而这种方案有些奇怪,故不常使用)。把立即函数的定义和调用都放在括号内,同样可以为JavaScript解析器指明它正在处理函数表达式。
image
不同于用加括号的方式区分函数表达式和函数声明,这里我们使用一元操作符+、-、!和~。这种做法也是用于向JavaScript引擎指明它处理的是表达式,而不是语句。

箭头函数

const myFun =()=>{ return 1;}
or 
var greet = name => "Greetings " + name;  //⇽--- 定义箭头函数”

image

注意这个新操作符——胖箭头符号=>(等号后面跟着大于号)是定义箭头函数的核心。

函数构造函数

new Function('a', 'b', 'return a + b')

生成器函数

function* myGen(){ yield 1; }

函数的实参和形参

  • 形参是我们定义函数时所列举的变量。
  • 实参是我们调用函数时所传递给函数的值。

image

函数形参是在函数定义时指定的,而且所有类型的函数都能有形参。

摘录来自: [美] John Resig Bear Bibeault Josip Maras. “JavaScript忍者秘籍(第2版)。” iBooks.

  • 函数声明(skulk函数的ninja形参)。
  • 函数表达式 (performAction函数的person和action形参)。
  • 箭头函数 (形参daimyo)。

从另一方面说,实参则与函数的调用相联系。它们是函数调用时所传给函数的值。

  • 字符串Hattori以函数实参的形式传递给函数skulk。
  • 字符串Oda Nobunaga以函数实参的形式传递给函数rule。
  • skulk函数的形参ninja作为实参传递给函数performAction。
可以这样理解哈:
函数声明和函数表达式,箭头函数,在声明的时候在括号里面的是形参,
函数调用时,传递给函数的是实参

剩余参数

function multiMax(first, ...remainingNumbers) {  ⇽--- 剩余参数以…作前缀
 var sorted = remainingNumbers.sort(function(a, b) {
   return b – a;   ⇽--- 以降序排序余下参数
 });
 return first * sorted[0];
}
assert(multiMax(3, 1, 2, 3) == 9,   ⇽--- 函数调用方式和其他函数类似
    "3*3=9 (First arg, by largest.)")

为函数的最后一个命名参数前加上省略号(...)前缀,这个参数就变成了一个叫作剩余参数的数组,数组内包含着传入的剩余的参数。

注意⚠️:只有函数的最后一个参数才能是剩余参数。

ES6中处理默认参数的方式

function performAction(ninja, action = "skulking"){   ⇽---  ES6中可以为函数的形参赋值
  return ninja + " " + action;
}

assert(performAction("Fuma") === "Fuma skulking",
    "The default value is used for Fuma");

assert(performAction("Yoshi") === "Yoshi skulking",
    "The default value is used for Yoshi");

assert(performAction("Hattori") === "Hattori skulking",
    "The default value is used for Hattori");  ⇽--- 若没传入值,则使用默认参数

assert(performAction("Yagyu", "sneaking") === "Yagyu sneaking",
    "Yagyu can do whatever he pleases, even sneak!");   ⇽--- 使用了传入的参数

小结

  • 把JavaScript看作函数式语言你就能书写复杂代码。
  • 作为第一类对象,函数和JavaScript中其他对象一样。类似于其他对象类型,函数具有以下功能。
  • 通过字面量创建。
  • 赋值给变量或属性。
  • 作为函数参数传递。
  • 作为函数的结果返回。
  • 赋值给属性和方法。
  • 回调函数是被代码随后“回来调用”的函数,它是一种很常用的函数,特别是在事件处理场景下。
  • 函数具有属性,而且这些属性能够被存储任何信息,我们可以利用这个特性来做很多事情;例如:
  • 可以在函数属性中存储另一个函数用于之后的引用和调用。
  • 可以用函数属性创建一个缓存(记忆),用于减少不必要的计算。
  • 有很多不同类型的函数:函数声明、函数表达式、箭头函数以及函数生成器等。
  • 函数声明和函数表达式是两种最主要的函数类型。函数声明必须具有函数名,在代码中它也必须作为一个独立的语句存在。函数表达式可以不必有函数名,但此时它就必须作为其他语句的一部分。
  • 箭头函数是JavaScript的一个新增特性,“这个特性让我们可以使用更简洁的方式来定义函数。
  • 形参是函数定义时列出的变量,而实参是函数调用时传递给函数的值。
  • 函数的形参列表和实参列表长度可以不同。
  • 未赋值的形参求值得到undefined。
  • 传入的额外实参不会被赋给任何一个命名形参。
  • 剩余参数和默认参数是JavaScript的新特性。
  • 剩余参数——不与任何形参名相匹配的额外实参可以通过剩余参数来引用。
  • 默认参数——函数调用时,若没传入参数,默认参数可以给函数提供缺省的参数值。
摘录来自: [美] John Resig Bear Bibeault Josip Maras. “JavaScript忍者秘籍(第2版)。” iBooks.
阅读 846

我相信:发光不是太阳的权利,每个人都可以。

17 声望
6 粉丝
0 条评论
你知道吗?

我相信:发光不是太阳的权利,每个人都可以。

17 声望
6 粉丝
宣传栏