好家伙,本篇为《JS高级程序设计》第十章“函数”学习笔记

1.函数的三种定义方式:函数表达式、函数声明及箭头函数

函数声明:

function sum(a) {
return a + 1;
}

函数表达式:

let sum= function(a){
return a + 1;
}

箭头函数:

let sum = (a) => {
return a + 1;
}

 

以函数声明方式声明的函数存在"函数声明提升",

在执行代码时,JavaScript 引擎会先执行一遍扫描, 把发现的函数声明提升到源代码树的顶部。

因此即使函数定义出现在调用它们的代码之后,引擎也会把 函数声明提升到顶部。

而函数表达式这么做会报错(箭头函数同样报错)

 代码如果没有执行到函数表达式的那一行,那么执行上下文中就没有函数的定义

2.函数名

函数名是指向函数的指针,所以它们跟其他包含对象指针的变量具有相同的行为。

function sum(num1, num2) {
return num1 + num2;
}
console.log(sum(10, 10)); // 20

let anotherSum = sum;

console.log(anotherSum(10, 10)); // 20

sum = null;

console.log(anotherSum(10, 10)); // 20

以上代码定义了一个名为 sum()的函数,用于求两个数之和。

然后又声明了一个变量 anotherSum, 并将它的值设置为等于 sum。

注意,使用不带括号的函数名会访问函数指针,而不会执行函数。

此时, anotherSum 和 sum 都指向同一个函数。

调用 anotherSum()也可以返回结果。把 sum 设置为 null 之后,就切断了它与函数之间的关联。

而 anotherSum()还是可以照常调用,没有问题。(有意思,之前不清楚)

ECMAScript 6 的所有函数对象都会暴露一个只读的 name 属性,其中包含关于函数的信息。

多数情 况下,这个属性中保存的就是一个函数标识符,或者说是一个字符串化的变量名。

即使函数没有名称, 也会如实显示成空字符串。

function AAA(){}

let BBB =function (){}

let CCC =()=>{}

console.log(AAA.name);
console.log(BBB.name);
console.log(CCC.name);
console.log((()=>{}).name);

 (最后一行有东西的,空字符)

3.参数

ECMAScript 函数的参数跟大多数其他语言不同。

ECMAScript 函数既不关心传入的参数个数,也不 关心这些参数的数据类型。

定义函数时要接收两个参数,并不意味着调用时就传两个参数。

你可以传一 个、三个,甚至一个也不传,解释器都不会报错。(好家伙)

4.没有重载

js没有重载

(这可真是太有意思了,方法名是指针,参数不管数量,我想js自然是不会有重载的)

方法后定义覆盖先定义(记住了,要考的)

function add(num) {
return num + 100;
}
function add(num) {
return num + 200;
}
let result = add(100); // 300

显然,定义两个同名参数,后定义的会覆盖先定义的

5.arguments属性

arguments 是一个类数组对象,包含调用函数时传入的所有参数。

function test(a,b,c,d,e){
console.log(arguments)
} test(1,2,3,4);

5.1.arguments.callee

arguments 对象其实还有一个 callee 属性,是一个指向 arguments 对象所在函数的 指针。

想不出什么好的例子,就用书中的原例吧:

(书中原例)

一个阶乘递归

function factorial(num) {
if (num <= 1) {
  return 1;
} else {
  return num * factorial(num - 1);
}
}

随后用arguments.callee代替factorial

function factorial(num) {
if (num <= 1) {
  return 1;
} else {
  return num * arguments.callee(num - 1);
}
}

这时候可能有人会问了,这有什么屌用.我刚开始也是这么想的,后来又看了两遍,发现js开发者还是有点东西的

使用 arguments.callee 就可以让函数逻辑与函数名解耦

我们接着看:

(重要的一个例子)

function factorial(num) {
if (num <= 1) {
return 1;
} else {
return num * arguments.callee(num - 1);
}
} let trueFactorial = factorial; factorial = function () {
return 0;
};
console.log(trueFactorial(5)); // 120
console.log(factorial(5)); // 0

 

这段就有意思了,

trueFactorial 变量被赋值为 factorial,所以console.log(trueFactorial(5));结果为120;

但是console.log(factorial(5)); 结果又为0;

trueFactorial 不受factorial方法重写的影响

这一个例子就帮我们记住了三个知识点:

1.函数名真的是指针

2.使用 arguments.callee 就可以让函数逻辑与函数名解耦

3.js有重写,莫得重载

6.caller属性

caller属性引用的是调用当前函数的函数,或者如果是 在全局作用域中调用的则为 null。

function outer() {
inner();
}
function inner() {
console.log(arguments.callee.caller);
}
outer();

 

第122篇: JS函数一些基本概念的更多相关文章

  1. UI5-技术篇-JS函数eval动态执行

    <html lang="en"> <head> <meta charset="utf-8" /> <title> ...

  2. 学好js,这些js函数概念一定要知道

    函数创建方式 1.声明方式 例如:function consoleTip (){ console.log("tip!"); } 2.表达式方式 例如:var consoleTip ...

  3. 前端总结·基础篇·JS(三)arguments、callee、call、apply、bind及函数封装和构造函数

    前端总结系列 前端总结·基础篇·CSS(一)布局 前端总结·基础篇·CSS(二)视觉 前端总结·基础篇·CSS(三)补充 前端总结·基础篇·JS(一)原型.原型链.构造函数和字符串(String) 前 ...

  4. 如何编写高质量的 JS 函数(1) -- 敲山震虎篇

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/7lCK9cHmunvYlbm7Xi7JxQ作者:杨昆 一千个读者,有一千个哈姆雷特. 此系列文 ...

  5. 如何编写高质量的 JS 函数(2) -- 命名/注释/鲁棒篇

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/sd2oX0Z_cMY8_GvFg8pO4Q作者:杨昆 上篇<如何编写高质量的 JS 函数 ...

  6. 如何编写高质量的 JS 函数(3) --函数式编程[理论篇]

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/EWSqZuujHIRyx8Eb2SSidQ作者:杨昆 [编写高质量函数系列]中, <如何 ...

  7. 如何编写高质量的 JS 函数(4) --函数式编程[实战篇]

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/ZoXYbjuezOWgNyJKmSQmTw作者:杨昆 [编写高质量函数系列],往期精彩内容: ...

  8. js函数与作用域,了解函数基本概念

    通过js基础语法了解到js的值包含数字,字符串和布尔值;js运算符分为算数,赋值,比较和逻辑运算符;js的流程控制包含条件判断if,switch选择;循环for while:下面js的函数及作用域,学 ...

  9. JS函数篇【2】

    什么是函数 函数的作用,可以写一次代码,然后反复地重用这个代码. <h3 onload="add2(1,2,3);add3(4,5,6)"></h3> &l ...

  10. AntDesign-React与VUE有点不一样,第一篇深入了解React的概念之一:JSX

    AntDesign-React与VUE有点不一样,第一篇深入了解React的概念之一:JSX 一.什么是JSX 使用JSX声明一个变量(REACT当中的元素): const element =< ...

随机推荐

  1. Redis-rdb-tools与rdr工具学习与使用

    Redis-rdb-tools与rdr工具学习与使用 简要说明 rdb工具是python写的一套工具,可以分析dump文件,获取key等信息. rdb其实有一套rdb-profiler工具, 能够导出 ...

  2. echarts轮训展示某个

    //学校资产占比的配置 function schollAssets() { var myChart = window.$echarts.init( document.getElementById('s ...

  3. vue3.0中reactive的正确使用姿势

    场景 在项目开发的时候,前端肯定是先写静态页面 在静态页面写好之后 然后就可以与后端对接数据了[高兴] 但是在对接接口的时候 我们会发现后端返回来的字段与前端在页面上写的可能不一致 这个时候有意思的事 ...

  4. Go 循环之for循环,仅此一种

    Go 循环之for循环,仅此一种 目录 Go 循环之for循环,仅此一种 一.for 循环介绍 二.for 循环结构 2.1 基本语法结构 2.2 省略初始值 2.3 省略初始语句和结束语句 2.4 ...

  5. vim 从嫌弃到依赖(15)——寄存器

    在计算机里面也有寄存器,计算机中的寄存器是看得见,摸得着的实体,寄存器中存储需要经常访问的一些数据.而vim中也有寄存器的概念,vim中的寄存器是一个虚拟的概念,更像是一块专门用来存储数据的内存缓冲区 ...

  6. 微信小程序-组件生命周期方法

    官方文档:https://developers.weixin.qq.com/miniprogram/dev/reference/api/Component.html 正如官方显示组件的生命周期中常用的 ...

  7. Swift中UITableViewDiffableDataSource的使用

    在 iOS 13 中 Apple 为 UITableView 和 UICollectionView 引入了 DiffableDataSource, 让开发者可以更简单高效的实现 UITableView ...

  8. 48从零开始用Rust编写nginx,搭建一个简单又好看官方网站

    wmproxy wmproxy已用Rust实现http/https代理, socks5代理, 反向代理, 负载均衡, 静态文件服务器,websocket代理,四层TCP/UDP转发,内网穿透等,会将实 ...

  9. 如何使用MBP制作Win启动盘

    最近有一个需求,想给家人的一台笔记本安装一套win 10的操作系统,但是我手头上现在没有对应的启动U盘. 由于工作原因,很多年没用win了,工作电脑也都是MBP,根本没有之前使用win时熟悉的Ultr ...

  10. SecureCRT使用sftp上传较大文件意外暂停

    今天在一台跳转机使用SecureCRT的sftp上传较大文件时,发现中途会时常停止传输,给出提示如下: 如果此时选择Accept Once,会继续传输,但是过一段时间后,还是会停止并给出相同提示,如果 ...