JavaScript的函数和作用域闭包
1. 函数
1.1 定义函数
function add(x, y){
return x + y;
}
上述函数定义如下:
- 关键字
function
指出这是一个函数定义; add
是函数的名称;(x, y)
括号内列出函数的参数,多个参数以,
分隔;{}
之间的代码是函数体,可以包含若干语句,甚至可以没有任何语句。
函数体内部的语句在执行时,一旦执行到return
时,函数就执行完毕,并将结果返回。
如果没有return
语句,函数执行完毕后也会返回结果,只是结果为undefined
。
JavaScript的函数也是一个对象,函数名可以视为指向该函数的变量。因此,函数也可以像下面这样定义。
var add = function (x, y){
return x + y;
}
这种情况下,function (x, y){}
是一个匿名函数,它没有函数名。但是,这个匿名函数赋值给了变量add
,所以,通过变量add
就可以调用该函数。
1.2 调用函数
调用函数时,按顺序传入参数即可。
add(1, 2); // 3
关键字arguments
只在函数内部起作用。我们通过arguments
可以获得调用者传入的所有参数。事实上,arguments
最常用于判断传入参数的个数。
function add(x, y){
for(let i = 0; i < arguments.length; i++){
console.log(arguments[i]);
}
return x + y;
}
console.log(add(1,5)); // 1 5 6
2. 作用域
2.1 概述
在JavaScript中,用var
声明的变量是有作用域的。
如果一个变量在函数体内声明,则该变量的作用域是整个函数体。
如果两个不同的函数各自声明了一个同名变量,那么这两个变量是相互独立的,互不影响。
由于JavaScript的函数可以嵌套,内部函数可以访问外部函数定义的变量,反过来则不行。
JavaScript的函数在查找变量时从自身函数定义开始,从"内"向"外"查找。
如果内部函数定义了与外部函数重名的变量,则内部函数的变量将"屏蔽"外部函数的变量。
2.2 变量提升
JavaScript会把变量声明提升到顶部。
function foo(){
console.log(x); // 不报错
var x = 'Hello';
}
// 等同于
function foo(){
var x;
console.log(x);
x = 'Hello';
}
3. 方法
在一个对象中绑定函数,称为这个对象的方法。
var me = {
name: '张三',
birth: 1994,
age: function(){
var y = new Date().getFullYear();
return y - this.birth;
}
};
console.log(me.age()); // 25
如果以对象的方法形式调用me.age()
,函数age()
的this
指被调用的对象me
。
3.1 apply
、call
、bind
var obj = {birth: 1990};
console.log(me.age.call(obj)); // 29
console.log(me.age.apply(obj)); // 29
let bind = me.age.bind(obj);
console.log(bind()); // 29
apply
、call
和bind
这三个函数的作用是改变函数执行时的上下文,即改变函数运行时的this
的指向。
apply
和call
改变了函数的this
上下文后便执行该函数,bind
则返回改变了上下文后的一个函数。apply
和call
的第一个参数都是要改变上下文的对象,而call
从第二个参数开始以参数列表的形式展现,apply
把除了改变上下文对象的参数放在一个数组里面作为它的第二个参数。
let arr1 = [1, 2, 10, 4];
//例子:求数组中的最值
console.log(Math.max.call(null, 1, 2, 10, 4)); // 10
console.log(Math.max.call(null, arr1)); // NaN
console.log(Math.max.apply(null, arr1)); // 10
5. 高阶函数
5.1 概述
JavaScript的函数接收变量作为参数,而函数名可以视为指向该函数的变量。因此,一个函数可以接收另一个函数作为参数。这种函数被称为高阶函数。
function add(x, y, f) {
return f(x) + f(y);
}
console.log(add(-5, 6, Math.abs)); // 11
内置对象Array
提供了一些高阶函数:
map
reduce
filter
sort
every
find
findIndex
forEach
相关阅读:JavaScript Array 对象
5.2 闭包
高阶函数除了可以接受函数作为参数外,还可以把函数作为结果值返回。
/*
function lazy_sum(arr) {
var sum = function () {
return arr.reduce(function (x, y) {
return x + y;
});
}
return sum;
}
*/
function lazy_sum(arr) {
return function () {
return arr.reduce(function (x, y) {
return x + y;
});
};
}
var f = lazy_sum([1, 2, 3, 4, 5]);
console.log(f()); // 15
在lazy_sum
函数中定义了函数sum
,sum
函数可以访问lazy_sum
函数的变量arr
(内部函数可以访问外部函数,参数可以看作函数中声明的变量)。当一个函数返回了一个函数后,相关的变量都保存在返回的函数中。
返回的sum
函数依然保持对lazy_sum
函数的作用域的引用,这个引用就叫作闭包。
注意:返回的函数没有立即执行,而是直到调用了f()
才执行。
使用闭包时要牢记一点是:返回函数不要引用任何循环变量,或者后续会发生变化的变量。
再看另一个例子。
var buildMultiplier = function(x) {
return function(y) {
return x * y;
}
}
var double = buildMultiplier(2);
var triple = buildMultiplier(3);
console.log(double(3)); // 6
console.log(triple(3)); // 9
参考:
- 函数定义和调用 - 廖雪峰的官方网站
- 方法 - 廖雪峰的官方网站
- 闭包 - 廖雪峰的官方网站
- 让你弄懂 call、apply、bind的应用和区别
- JavaScript 高阶函数 · 学习JavaScript
JavaScript的函数和作用域闭包的更多相关文章
- 浅谈JavaScript的函数表达式(闭包)
前文已经简单的介绍了函数的闭包.函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数. var Super=function(num){ var count=num; retu ...
- 我所理解的javascript中函数的作用域和作用域链
本文为原创,转载请注明出处: cnzt 文章:cnzt-p 写在前面 一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看 ...
- python基础(7)-函数&命名空间&作用域&闭包
函数 动态参数 *args def sum(*args): ''' 任何参数都会被args以元组的方式接收 ''' print(type(args)) # result:<class 'tupl ...
- 函数嵌套>作用域>闭包函数
一:函数对象 函数是第一类对象,即表示函数可以当做数据传递 可以被引用:把函数内存地址赋值给一个变量名,仍然遵循函数的调用规则. 可以被当做参数传递:传递的是函数的运行的结果#可以当做返回值 把函数作 ...
- 10 - 函数嵌套-作用域-闭包-LEGB-函数销毁
目录 1 函数嵌套 2 作用域 2.1 global关键字 3 闭包 3.1 nonlocal关键字 4 默认值的作用域 5 变量名解析原则LEGB 6 函数的销毁 1 函数嵌套 一个 ...
- (二)JavaScript之[函数]与[作用域]
3].函数 /** * 事件驱动函数. * 函数执行可重复使用的代码 * * 1.带参的函数 * 2.带返回值的函数 * 3.局部变量 * * 4.全局变量 * 在函数外的:不用var声明,未声明直接 ...
- [译]JavaScript:函数的作用域链
原文:http://blogs.msdn.com/b/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx 在JavaScr ...
- JavaScript函数及作用域
知识内容: 1.JavaScript函数 2.JavaScript全局函数及特殊函数 3.JavaScript作用域 4.本节练习 参考资料:<JavaScript高级程序设计> 一.Ja ...
- 【转载】【翻译】JavaScript Scoping and Hoisting--JS作用域和变量提升的探讨
原文链接:http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting 你知道下面的JavaScript代码执行后会aler ...
随机推荐
- java 数据结构(七):Collection接口
1.单列集合框架结构|----Collection接口:单列集合,用来存储一个一个的对象* |----List接口:存储序的.可重复的数据. -->“动态”数组* |----ArrayList. ...
- java 面向对象(十一):关键字:package/import
1.1 使用说明: * 1.为了更好的实现项目中类的管理,提供包的概念 * 2.使用package声明类或接口所属的包,声明在源文件的首行 * 3.包,属于标识符,遵循标识符的命名规则.规范(xxxy ...
- CRM【第二篇】: stark组件
介绍: stark组件,是一个帮助开发者快速实现数据库表的增删改查+的组件.目标: 10s 中完成一张表的增删改查. 前戏: django项目启动时,自定义执行某个py文件. django启动时,且在 ...
- oracle数据库备份还原命令
oracle数据库备份命令exp 用户名/密码@orcl file=d:\xxxxxx.dmp owner=用户名 oracle数据库还原命令sqlplus conn / as sysdba drop ...
- OSCP Learning Notes - Enumeration(2)
HTTP Enumeration Target Host IP: 10.0.0.20 Brute Forcing using DirBuster 1. Start the dirbuster and ...
- 洛谷 P5350 序列 珂朵莉树
题目描述 分析 操作一.二.三为珂朵莉树的基本操作,操作四.五.六稍作转化即可 不会珂朵莉树请移步至这里 求和操作 把每一段区间分别取出,暴力相加 ll qh(ll l,ll r){ it2=Spli ...
- 谷歌浏览器扩展 crx 下载
下方服务可让国内成功下载谷歌浏览器.crx 扩展,如谷歌浏览器无法安装,可以使用终极解决方法,把.crx 解压缩,然后在扩展中心中开启 开发者模式然后选择加载已解压的扩展程序. 需要注意的是解压缩的文 ...
- 如何在Python对Excel进行读取
在python自动化中,经常会遇到对数据文件的操作,比如添加多名员工,但是直接将员工数据写在python文件中,不但工作量大,要是以后再次遇到类似批量数据操作还会写在python文件中吗? 应对这一问 ...
- python如何编写win程序
python可以编写win程序.win程序的格式是exe,下面我们就来看一下使用python编写exe程序的方法. 编写好python程序后py2exe模块即可将其打包为exe程序. 实际操作过程: ...
- Qt-操作xml文件
1 简介 参考视频:https://www.bilibili.com/video/BV1XW411x7AB?p=12 xml简介:可扩展标记语言,标准通用标记语言的子集,简称XML.是一种用于标记电 ...