这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战
函数作为JS的一等公民,既可以返回函数,也可以把函数作为另一个函数的参数使用,同时还有一种更奇妙的用法,函数还可以像其他对象一样添加属性,你知道吗?有图为证:
函数作为对象的乐趣
(1)存储函数
在集合中存储函数使我们轻易管理相关联的函数。例如,某些特定情况下必须调用的回调函数。
场景:例如,我们需要管理某个事件发生后需要调用的回调函数集合,我们会存储元素唯一的函数集合。当我们向这样的集合中添加函数时,会面临两个问题:哪个函数对于这个集合来说是一个新函数,从而需要被加入到该集合中?又是哪个函数已经存在于集合中,从而不需要再次加入到集合中?一般来说,管理回调函数集合时,我们并不希望存在重复函数,否则一个事件会导致同一个回调函数被多次调用。
实现方法就是借用了函数可以增加属性的技巧:
在这个例子中,我们创建了一个对象赋值给变量store,这个变量中存储的是唯一的函数集合。这个对象有两个数据属性:其一是下一个可用的id,另外一个缓存着已经保存的函数。函数通过add()方法添加到缓存中。在add函数内,我们首先检查该函数是否已经存在id属性。如果当前的函数已经有id属性,我们则假设该函数已经被处理过了,从而忽略该函数,否则为该函数分配一个id(同时增加nextId)属性,并将该函数作为一个属性增加到cache上,id作为属性名。
(2)自记忆函数
记忆让函数能记住上次计算得到的值,从而提高后续调用的性能。记忆化(memoization)是一种构建函数的处理过程,能够记住上次计算结果。
在isPrime函数中,首先通过检查它的answers属性来确认是否已经创建了一个缓存,如果没有创建,则新建一个;只有第一次函数调用才会创建这个初始空对象,之后这个缓存就已经存在了。然后我们会检查参数中传的值是否已经存储到缓存中,如果我们在缓存中找到该值,函数会直接返回。
回调函数
定义
即在执行过程中,我们建立的函数会被其他函数在稍后的某个合适时间点“再回来调用”。
回调函数在哪种情况下会同步调用,或者异步调用呢?
事件是异步的:
● 浏览器事件,例如当页面加载完成后或无法加载时;
● 网络事件,例如来自服务器的响应(Ajax事件和服务器端事件);
● 用户事件,例如鼠标单击、鼠标移动和键盘事件;
● 计时器事件,当timeout时间到期或又触发了一次时间间隔。
箭头函数和函数表达式的区别是什么?
- 箭头函数是匿名函数,不能作为构造函数,不能使用new
- 箭头函数不绑定arguments,取而代之用rest参数...解决
- 箭头函数不绑定this,会捕获其所在的上下文的this值,作为自己的this值。任何方法都改变不了其指向
- 普通函数的this指向调用它的那个对象
函数中两个隐含的参数:arguments和this
参数this表示被调用函数的上下文对象;参数this表示被调用函数的上下文对象,而arguments参数表示函数调用过程中传递的所有参数。
arguments
arguments 并不是真正的数组而是类数组,在大多数情况下可以使用剩余参数(rest parameter)来代替arguments参数。剩余参数是真正的Array实例。
- arguments对象作为函数参数的别名,即
arguments[下标]
this:函数上下文
this参数是面向对象JavaScript编程的一个重要组成部分,代表函数调用相关联的对象。因此,通常称之为函数上下文。
它的值受函数调用方式的影响而不同:
(1)作为函数被调用 如以下调用方式:
当以这种方式调用时,函数上下文(this关键字的值)有两种可能性:
-
在非严格模式下,它将是全局上下文(window对象)
-
在严格模式下,它将是undefined。
(2)作为方法被调用 函数作为对象的一个属性调用,被称为方法。当函数作为某个对象的方法被调用时,该对象会成为函数的上下文,并且在函数内部可以通过参数访问到。
但方法不能用箭头函数。
因为箭头函数是本身没有执行的上下文,没有本身的this 就要找离他最近的一个执行环境作为执行上下文。也就是说如果在对象中的方法使用箭头函数,那么它的this指向为 window,并不会如我们期望的该对象本身。
(3)作为构造函数 构造函数与普通函数一样,可以通过函数声明或函数表达式来实现,唯一的不同就是调用方法不同。 构造函数在调用的时候需要使用 new 关键字
new 关键字做了以下4件事: 1.创建一个新的对象 2.将构造函数的作用域赋给新对象(因此 this 就指向了这个新对象) ; 3.执行构造函数中的代码(为这个新对象添加属性) ; 4.返回新对象
使用构造函数的一些注意事项:
- 如果构造函数返回一个对象,则该对象将作为整个表达式的值返回,而传入构造函数的this将被丢弃。
- 但是,如果构造函数返回的是非对象类型,则忽略返回值,返回新创建的对象。
(4)通过 call() 或 apply()、bind() 方法
由上文可知:不同类型函数调用之间的主要区别在于:最终作为函数上下文(可以通过this参数隐式引用到)传递给执行函数的对象不同。
如果我们需要显示改变 this 指向,那就用到了 call() 或 apply() 方法
文章参考:《JavaScript 忍者秘籍》