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 applycallbind

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

applycallbind这三个函数的作用是改变函数执行时的上下文,即改变函数运行时的this的指向。

  • applycall改变了函数的this上下文后便执行该函数,bind则返回改变了上下文后的一个函数。
  • applycall的第一个参数都是要改变上下文的对象,而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函数中定义了函数sumsum函数可以访问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

参考

JavaScript的函数和作用域闭包的更多相关文章

  1. 浅谈JavaScript的函数表达式(闭包)

    前文已经简单的介绍了函数的闭包.函数的闭包就是有权访问另一个函数作用域的函数,也就是函数内部又定义了一个函数. var Super=function(num){ var count=num; retu ...

  2. 我所理解的javascript中函数的作用域和作用域链

    本文为原创,转载请注明出处: cnzt       文章:cnzt-p 写在前面 一周木有更新了,今天终于攻克了自行车难关,非常开心,特意来一更~ (那些捂嘴偷笑的人我看到你们了快把嘴闭上我会假装没看 ...

  3. python基础(7)-函数&命名空间&作用域&闭包

    函数 动态参数 *args def sum(*args): ''' 任何参数都会被args以元组的方式接收 ''' print(type(args)) # result:<class 'tupl ...

  4. 函数嵌套>作用域>闭包函数

    一:函数对象 函数是第一类对象,即表示函数可以当做数据传递 可以被引用:把函数内存地址赋值给一个变量名,仍然遵循函数的调用规则. 可以被当做参数传递:传递的是函数的运行的结果#可以当做返回值 把函数作 ...

  5. 10 - 函数嵌套-作用域-闭包-LEGB-函数销毁

    目录 1 函数嵌套 2 作用域 2.1 global关键字 3 闭包 3.1 nonlocal关键字 4 默认值的作用域 5 变量名解析原则LEGB 6 函数的销毁 1 函数嵌套         一个 ...

  6. (二)JavaScript之[函数]与[作用域]

    3].函数 /** * 事件驱动函数. * 函数执行可重复使用的代码 * * 1.带参的函数 * 2.带返回值的函数 * 3.局部变量 * * 4.全局变量 * 在函数外的:不用var声明,未声明直接 ...

  7. [译]JavaScript:函数的作用域链

    原文:http://blogs.msdn.com/b/jscript/archive/2007/07/26/scope-chain-of-jscript-functions.aspx 在JavaScr ...

  8. JavaScript函数及作用域

    知识内容: 1.JavaScript函数 2.JavaScript全局函数及特殊函数 3.JavaScript作用域 4.本节练习 参考资料:<JavaScript高级程序设计> 一.Ja ...

  9. 【转载】【翻译】JavaScript Scoping and Hoisting--JS作用域和变量提升的探讨

    原文链接:http://www.adequatelygood.com/2010/2/JavaScript-Scoping-and-Hoisting 你知道下面的JavaScript代码执行后会aler ...

随机推荐

  1. java 面向对象(二十九):异常(二)异常的处理

    1.java异常处理的抓抛模型过程一:"抛":程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象. * 并将此对象抛出. * 一旦抛出对象以后,其后的代 ...

  2. 数据可视化之powerBI技巧(四)使用Power BI制作帕累托图

    各种复杂现象的背后,其实都是受关键的少数因素和普通的大多数因素所影响,把主要精力放在关键的少数因素上,就能达到事半功倍的效果. 这就是大家常说的二八原则,也称为帕累托原则,最早是由意大利经济学家 V. ...

  3. Django之Model、Form、ModelForm区别

    本节内容: 1:Model               https://www.cnblogs.com/shuai1991/p/10844662.html 2:Form                 ...

  4. mysql中常见约束

    #常见约束 /* 含义:一种限制,用于限制表中的数据,为了保证表中的数据的准确和可靠性 分类:六大约束 NOT NULL:非空,用于保证该字段的值不能为空 比如姓名.学号等 DEFAULT:默认,用于 ...

  5. 计算思维(Computational Thinking)在少儿编程中的体现

    本文主要针对少儿编程从业人员及正在学习编程的学生家长 大家好,我是C大叔,国内早期的少儿编程从业人员.一直以来都是在做scratch,JavaScript,python以及信息学奥赛C++的讲师,教研 ...

  6. Java顺序查找、二分查找

    Java顺序查找.二分查找   查找算法中顺序查找算是最简单的了,无论是有序的还是无序的都可以,只需要一个个对比即可,但其实效率很低. 顺序查找 动图演示 详细代码 // 顺序查找 public st ...

  7. css:实现文本两行或多行文本溢出显示省略号

    div{ display: -webkit-box; -webkit-box-orient: vertical; word-break: break-all; word-wrap: break-wor ...

  8. sqlserver——merge用法

    merge集插入,更新,删除于一体,如果要对一个表同时进行插入,更新,删除2个或3三个操作.效率要高于单个操作. merge into tableb b --被操作表using (select id, ...

  9. italic和oblique的区别

    italic和oblique都是向右倾斜的文字, 但区别在于Italic是指斜体字,而Oblique是倾斜的文字(让没有斜体属性的文字倾斜), 对于没有斜体的字体应该使用Oblique属性值来实现倾斜 ...

  10. Element 季度选择器+导入

    苦恼于element没有季度选择器,网上搜罗后整理实现,以便后期开发使用 同文件夹下新建一个vue界面,命名为Quarter.vue <template> <el-form> ...