函数是一段可以反复调用的代码块。函数还能接受输入的参数,不同的参数会返回不同的值

声明函数的 5 种方式

  • 具名函数 (function 命令)

     function f(x, y){
    return x + y;
    }
    f.name // 'f'
  • 函数表达式

    var f
    f = function(x, y){
    return x + y;
    }
    f.name // 'f'
  • 具名函数赋值

    var f
    f = function f2(x, y){
    return x + y;
    }
    f.name // 'f2'
    console.log(f2) // undefined
  • window.Function

    var f = new Function('x', 'y', 'return x + y;')
    f.name // 'anonymous'
  • 箭头函数

    var f = (x, y) => {
    return x + y;
    }
    var sum = (x, y) => x + y
    var n2 = n => n*n

函数的特性

  • 如果同一个函数被多次声明,后面的声明就会覆盖前面的声明

  • 函数内部的return语句表示返回,JavaScript 引擎遇到return语句,就直接返回return后面的哪个表达式的值,即时后面还有语句也不会得到执行。return语句不是必须的,如果没有,函数默认返回undefined

  • 在 JavaScript 中函数可以看成一个种值,与其他值(数字,字符串,布尔值等)地位相同,称为第一等公民,函数可以当作惭怍传递给另外一个函数。

  • 函数名的提升

    JavaScript 引擎将函数名视同变量名,所以采用function命令声明函数时,整个函数会像变量声明一样,被提升到代码头部,所以,下面的代码不会出错。

    f();
    
    function f() {}
    // 表面上,代码好像在声明之前就调用了函数f。
    // 但是实际上,由于“变量提升”,函数 f 被提升到了代码头部,也就是在调用之前已经声明了

    如果使用函数表达式的方式,声明前就调用,下面的代码就会出错

    f();
    var f = function (){}
    // TypeError: f is not a function // 等价于
    var f;
    f();
    f = function(){}

函数作用域

作用域(scope)指的是变量存在的范围,在 ES5 的规范中只有全局作用域和函数作用域,ES6 新增了块级作用域。

全局作用域:变量在整个程序中一直存在,所有地方都可以读取

函数作用域:变量只在函数内部存在,外部无法访问函数内部的变量,除了使用闭包。

  • 函数内部可以读取全局变量

    var v = 1;
    
    function f() {
    console.log(v);
    } f()
    // 1
  • 在函数内部定义的变量,外部无法读取,称为“局部变量”

    function f(){
    var v = 1;
    } v // ReferenceError: v is not defined
  • 函数内部定义的变量,会在该作用域内覆盖同名全局变量,就近原则

    var v = 1;
    
    function f(){
    var v = 2;
    console.log(v);
    } f() // 2
    v // 1
  • 与全局作用域一样,函数作用域内部也会产生“变量提升”现象。var命令声明的变量,不管在什么位置,变量声明都会被提升到函数体的头部

    function foo(x) {
    if (x > 100) {
    var tmp = x - 100;
    }
    } // 等同于
    function foo(x) {
    var tmp;
    if (x > 100) {
    tmp = x - 100;
    };
    }
  • 函数本身也是一个值,也有自己的作用域。它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。参考本文中的 题目二

闭包

function f1() {
var n = 999;
function f2() {
console.log(n);
}
return f2;
} var result = f1();
result(); // 999

函数 f2 和变量 n 的组合就形成了一个闭包。

「函数」和「函数内部能访问到的变量」(也叫环境)的总和,就是一个闭包

闭包的作用:

闭包常常用来「间接访问一个变量」。换句话说,「隐藏一个变量」,让函数执行形成的私有作用域,保护里面的变量不受外界干扰的机制。

var api = (function() {
var lives = 50
var 奖励一条命 = function() {
lives += 1
console.log('当前剩余' + lives)
}
var 死一条命 = function() {
lives -= 1
console.log('当前剩余' + lives)
}
return {
a: 奖励一条命,
b: 死一条命
} }())
api.a() // 当前剩余51
api.b() // 当前剩余50
api.b() // 当前剩余49

参考阅读 JS 中的闭包是什么

立即执行函数

(function(){
/* code */
}()); // 或者 (function(){
/* code */
})();

通常情况下,只对匿名函数使用这种“立即执行的函数表达式”。

它的目的有两个:

一是不必为函数命名,避免了污染全局变量;

二是 IIFE 内部形成了一个单独的作用域,可以封装一些外部无法读取的私有变量。

练习题

题目一

var a = 1
function f1(){
alert(a) // 是多少
var a = 2
}
f1.call() // 遇到代码题,请先提升声明!
// 遇到代码题,请先提升声明!
// 遇到代码题,请先提升声明! var a = 1
function f1(){
var a
alert(a)
a = 2
}
f1.call()
// 答案: alert 一个 undefined

题目二

var a = 1
function f1(){
var a = 2
f2.call()
}
function f2(){
console.log(a) // 是多少
}
f1.call()
// 函数本身也是一个值,也有自己的作用域。
// 它的作用域与变量一样,就是其声明时所在的作用域,与其运行时所在的作用域无关。 // 答案:输出 1

题目三

var liTags = document.querySelectorAll('li')
for(var i = 0; i<liTags.length; i++){
liTags[i].onclick = function(){
console.log(i) // 点击第3个 li 时,打印 2 还是打印 6?
}
} // 答案 6 // 如何解决?
// 1. 使用 let 声明变量 i
// 2. 使用立即执行函数 var liTags = document.querySelectorAll('li')
for (var i = 0; i < liTags.length; i++) {
(function(item) {
liTags[item].onclick = function() {
console.log(item)
}
})(i); }

JS 函数 学习笔记的更多相关文章

  1. js再学习笔记

    #js再学习笔记 ##基本 1.js严格区分大小写   2.js末尾的分号可加,也可不加   3.六种数据类型(使用typeof来检验数据的类型) `typeof` - undefined: `var ...

  2. JS数组学习笔记

    原文:JS数组学习笔记 最近在备课数组,发现很多ES5的方法平时很少用到.细节比较多,自己做了大量例子和整理,希望对大家了解JavaScript中的Array有所帮助. 概念 数组是值的有序集合.每个 ...

  3. C++学习基础十六-- 函数学习笔记

    C++ Primer 第七章-函数学习笔记 一步一个脚印.循序渐进的学习. 一.参数传递 每次调用函数时,都会重新创建函数所有的形参,此时所传递的实参将会初始化对应的形参. 「如果形参是非引用类型,则 ...

  4. Knockout.js快速学习笔记

    原创纯手写快速学习笔记(对官方文档的二手理解),更推荐有时间的话读官方文档 框架简介(Knockout版本:3.4.1 ) Knockout(以下简称KO)是一个MVVM(Model-View-Vie ...

  5. handlebars.js基础学习笔记

    最近在帮学校做个课程网站,就有人推荐用jquery+ajax+handlebars做网站前端,刚接触发现挺高大上的,于是就把一些基础学习笔记记录下来啦. 1.引用文件: jquery.js文件下载:h ...

  6. JS&ES6学习笔记(持续更新)

    ES6学习笔记(2019.7.29) 目录 ES6学习笔记(2019.7.29) let和const let let 基本用法 let 不存在变量提升 暂时性死区 不允许重复声明 块级作用域 级作用域 ...

  7. 两万字Vue.js基础学习笔记

    Vue.js学习笔记 目录 Vue.js学习笔记 ES6语法 1.不一样的变量声明:const和let 2.模板字符串 3.箭头函数(Arrow Functions) 4. 函数的参数默认值 5.Sp ...

  8. 两万字Vue.js基础学习笔记(二)

    Vue.js学习笔记(二) 4.模块化开发 ES6模块化的导入和导出 我们使用export指令导出了模块对外提供的接口,下面我们就可以通过import命令来加载对应的这个模块了 首先,我们需要在HTM ...

  9. Node.js API 学习笔记

    常用 API 学习笔记 url 函数 url.parse: 解析 url 地址 url.resolve: 向 url 地址添加或替换字段 url.format: 生成 url 地址 querystri ...

随机推荐

  1. 解决SVN异常 cleanup failed

    winndows上偶尔使用SVN的时候就会整出一些有的没的问题,比如"cleanup failed to process the following paths previous opera ...

  2. highlight语法高亮推荐样式

    最近在弄一个类似博客的东西,需要高亮显示代码,所以用了highlight.js来完成 highlight提供了不同的风格我们可以通过更改css样式表来找到适合我们的. 我罗列一部分看看有哪些风格 以下 ...

  3. BitMap位图

    BitMap位图算法https://blog.csdn.net/varyall/article/details/79662029 常见面试题 题1:在2.5亿个整数找出不重复的整数,内存不足以容纳着2 ...

  4. dsu on tree 学习笔记

    这是一个黑科技,考虑树链剖分后,每个点只会在轻重链之间转化\(log\)次. 考虑暴力是怎么写的,每次枚举一个点,再暴力把子树全部扫一边. \(dsu\ on\ tree.\)的思想就是保留重儿子不清 ...

  5. css 鼠标经过图片缓慢切换图片、鼠标离开缓慢还原

    https://blog.csdn.net/qq_26780317/article/details/80486766 一.控制背景图片在一个圆形div内切换 .header .logo { width ...

  6. Vue 组件间的传值(通讯)

    组件之间的通讯分为三种 父给子传 子给父传 兄弟组件之间的通讯 1 父组件给子组件传值 子组件嵌套在父组件内部,父组件给子组件传递一个标识,在子组件内部用props接收,子组件在模板里可以通过{{}} ...

  7. struts2+ajax 前后端传值

    摘要: 主要实现步骤如下: 1.JSP页面使用脚本代码执行ajax请求 2.Action中查询出需要返回的数据,并转换为json类型模式数据 3.配置struts.xml文件 4.页面脚本接受并处理数 ...

  8. QTimer不能同时使用两个,用QTimerEvent (QT)

    最近写程序的时候有个界面想定两个QTimer定时器,不同时间干不同的事: QTimer *timer1 = new QTimer(this); QTimer *timer2 = new QTimer( ...

  9. Eclipse 4.9 创建springboot项目步骤

    上一篇文章写了eclipse安装STS. 现在创建Spring Starter Project  具体步骤如下: 1.等你安装好STS后,就在Eclipse >  File >New 选择 ...

  10. python之路----操作系统的发展史

    阅读目录 手工操作 —— 穿孔卡片 批处理 —— 磁带存储和批处理系统 多道程序系统 分时系统 实时系统 通用操作系统 操作系统的进一步发展 操作系统的作用 手工操作 —— 穿孔卡片 1946年第一台 ...