写在前面

注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者。有发现什么问题的,欢迎留言指出。

1.函数声明和函数表达式

函数声明具有声明提前/声明提升的特性,这一点和变量的声明特性相似,执行代码之前会先读取函数声明和变量声明,意味着可以把函数声明放在调用它的语句后面,但变量声明肯定最好不要这样,因为常伴随undefined问题。

函数声明的函数名称和函数体都提前,而函数表达式只是变量声明提前(而变量的初始化代码仍然在原来的位置)。

2.函数调用

构成函数主体的代码定义时并不会执行,调用函数时才会执行,有4中方式调用函数:

  • 作为函数
  • 作为方法
  • 作为构造函数
  • 通过call()和apply()方法间接调用

①作为函数调用的注意点,严格模式下调用上下文是undefined,所以通常不使用this关键字,②作为方法调用的话调用上下文就是方法所在的对象,this关键字引用着该对象。③而嵌套函数不会从调用它的函数中继承this,如果想访问外部的this,可以用变量保存this的值。④构造函数调用会使用新创建的对象作为调用上下文。

3.函数的参数相关

  • 可选形参

当传入的实参比函数声明时指定的形参数量要少,剩下的形参都将设置为undefined值(实参多则会自动省略)。所以在合适的场景就可以选择使用可选形参:

function getPropertyNames(o, /* optional */ a) {
if(a=== undefined) a=[];
for(var prop in o) a.push(prop);
return a;
}
var arr = [1,2];
//[1, 2, "x", "y"]
console.log(getPropertyNames({x:1,y:2},arr));
//["x", "y"]
console.log(getPropertyNames({x:1,y:2}));

注意点:需要将可选形参放在形参列表的最后,并在函数定义是使用注释强调形参是可选的。

  • 实参对象arguments

在函数体内,标识符arguments是指向实参对象的引用,它是一个类数组对象,可以通过数字下标访问传入的实参值,这样函数就可以操作任意数量的实参:

function getMaxValue(/* ... */) {
var max = arguments[0];
for(var i=0,len=arguments.length;i<len;i++){
if(arguments[i]>max){
max = arguments[i];
}
}
return max;
}
console.log(getMaxValue(4,2,1,8,10));//10
  • 将对象属性用作实参:当一个函数的形参过多(比如超过3个),调用时记住实参的正确顺序不容易。这时可以把形参写成一个对象,就没有参数顺序的影响了,而且还可以在取值的时候使用||符号设置默认值。当然,形参不多就不需这样做,效率会低一些。

  • 在每个形参左边使用类似/*array*/的类型注释。在函数体内应该要有实参类型检查的逻辑,在传入非法值时报错。

  • 自定义函数属性:函数是一种特殊的对象,所以在适当的时候可以给函数定义属性,比如函数需要一个“静态变量”:

//阶乘
function factorial(n) {
if(isFinite(n) && n>0 && n==Math.round(n)){
if(!(n in factorial)) factorial[n] = n * factorial(n-1);
return factorial[n];
}
else return NaN;
}
factorial[1] = 1;
console.log(factorial([5]));//120

4.作为命名空间的函数

为了不污染全局空间,常用定义匿名函数并立即在单个表达式中调用的方式:

var extendFun = (function () {
//函数体
}());

5.call()、apply()和bind()

  • call()和apply()

call()和apply()是函数的方法,通过调用方法的形式来简介调用函数,我们之前介绍继承的时候,有一个地方是借用超类型的构造函数,就是使用了call。它们的第一个实参是要调用函数的母对象,它是调用上下文,函数体内通过this引用它

call除了第一个参数之后的参数就是要传给函数的值:

function logMsg(x,y,z) {
console.log(x+'/'+y+'/'+z);
}
//打印2/4/6
logMsg.call({},2,4,6);

而apply除了第一个参数以外,提供一个数组用于传给函数:

function logMsg(x,y,z) {
console.log(x+'/'+y+'/'+z);
}
//打印8/10/12
logMsg.apply({},[8,10,12]);

apply的数组参数可以是真实数组,也可以是类数组对象,比如可以把当前函数的arguments数组直接传入:

function logMsg(x,y,z) {
console.log(x+'/'+y+'/'+z);
}
function wantToLog(a,b,c) {
logMsg.apply({},arguments);
}
//打印1/2/3/4
wantToLog(1,2,3);
  • bind()

这个方法主要作用是将函数绑定至某个对象,除了第一个实参以外,其他的实参会传入到函数里面:

function f(y,z) {
console.log("y:"+y);//y:4
console.log("z:"+z);//z:2
return this.x + y + z;
}
var g = f.bind({x:3},4);
console.log(g(2));//3+4+2=9
//这里面绑定了this和y

js知识梳理5:关于函数的要点梳理(1)的更多相关文章

  1. js知识梳理6:关于函数的要点梳理(2)(作用域链和闭包)

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  2. js知识梳理4.继承的模式探究

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  3. js知识梳理3:创建对象的模式探究

    写在前面 注:这个系列是本人对js知识的一些梳理,其中不少内容来自书籍:Javascript高级程序设计第三版和JavaScript权威指南第六版,感谢它们的作者和译者.有发现什么问题的,欢迎留言指出 ...

  4. JS中的自执行函数

    本来规划的是2013年,狠狠的将JS学习下,谁知计划赶不上变化,计划泡汤了.13年的我对JS来说可以说是属于跟风,对它的理解和认识也仅仅是皮毛而已,也是因为要完成<ArcGIS API for ...

  5. 从浏览器多进程到JS单线程,JS运行机制最全面的一次梳理

    前言 来源:https://dailc.github.io/2018/01/21/js_singlethread_eventloop.html 见解有限,如有描述不当之处,请帮忙及时指出,如有错误,会 ...

  6. 安全测试 + 渗透测试 Xmind 要点梳理

    从事测试工作多年,一直对安全测试充满神秘感.买了本书,闲来无事时翻看了解.发现书的开头提供的Xmind脑图挺有参考价值,所以做了次“搬运工”,提供给想接触了解安全测试/渗透测试的小伙伴. 安全测试要点 ...

  7. JS中的高阶函数

    JS中的高阶函数 高阶函数是指以函数作为参数的函数,并且可以将函数作为结果返回的函数. 1. 高阶函数 接受一个或多个函数作为输入 输出一个函数 至少满足以上一个条件的函数 在js的内置对象中同样存在 ...

  8. js原生的url操作函数,及使用方法。(附:下边还有jquery对url里的中文解码函数)

    js原生的url操作函数,完善的. /*****************************/ /* 动态修改url */ /*****************************/ var ...

  9. JS通用事件监听函数

    JS通用事件监听函数 版本一 //把它全部封装到一个对象中 var obj={ readyEvent:function (fn){ if(fn==null){ fn=document; } var o ...

随机推荐

  1. 『现学现忘』Docker常用命令 — 19、容器常用命令(一)

    目录 1.新建并启动容器 2.列出当前所有正在运行的容器 3.退出容器 4.启动容器 5.重启容器 6.停止容器 7.强制停止容器 8.删除已停止的容器 有镜像才能创建容器,这是根本前提. 我们下载一 ...

  2. vscode中使用git

    vscode中使用git 使用vscode打开git的文件时,会自动的跟踪文件的改动, 如果要提交修改,首先点击+,这个相当于git add, 这样会暂时保存,然后点击上面的√,然后在输入栏中输入修改 ...

  3. collections 数据类型扩展模块

    在内置数据类型(dict.list.set.tuple)的基础上,collections模块还提供了几个额外的数据类型:Counter.deque.defaultdict.namedtuple和Ord ...

  4. 【论文阅读】CVPR2022: Learning from all vehicles

    Column: March 23, 2022 1:08 PM Last edited time: March 23, 2022 11:13 PM Sensor/组织: 现leaderboard第一名, ...

  5. CF1430F Realistic Gameplay (贪心+DP)

    朴素做法暴力DP,O(nk)过不去... 1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 ...

  6. IO笔记(学习尚硅谷java基础教程)

    一.基础知识 1. 在普通方法和测试方法中文件路径的差异 在普通方法中:文件路径相当于在当前项目中,而不是当前Module(以项目为基准) 在测试方法中:文件路径相当于在当前Module中,而不是当前 ...

  7. 什么是 Hystrix?它如何实现容错?

    Hystrix 是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性.通常对于使用微服 构开发的系统,涉及到许多微服务 ...

  8. kafka producer如何优化打入速度?

    增加线程 提高 batch.size 增加更多 producer 实例 增加 partition 数 设置 acks=-1 时,如果延迟增大:可以增大 num.replica.fetchers(fol ...

  9. Springmvc入门基础(四) ---参数绑定

    1.默认支持的参数类型 处理器形参中添加如下类型的参数处理适配器会默认识别并进行赋值. 除了ModelAndView以外,还可以使用Model来向页面传递数据, Model是一个接口,在参数里直接声明 ...

  10. 用 Java 写一个折半查找?

    折半查找,也称二分查找.二分搜索,是一种在有序数组中查找某一特定元素的搜索算法. 搜素过程从数组的中间元素开始,如果中间元素正好是要查找的元素,则搜素过程结束:如果某一特定元素大于或者小于中间元素,则 ...