作者 | Jeskson

来源 | 达达前端小酒馆

定义函数的方式:

第一种为 函数声明; 第二种为 函数表达式。

语法:

function functionName(arg0, arg1, arg2) {// 函数体
}

在Firefox,Safari,Chrome和Opera有效:

就是通过这个属性可以访问到这个函数指定的名字。

console.log(functionName.name); // 'functionName'

函数声明:

它的一个重要特点就是:函数声明提升,就是在执行代码前先读取函数声明,可以把函数声明放在调用它的语句后。

// 调用函数
dada();
// 函数声明
function dada() {console.log('dada');
}

使用函数表达式,函数表达式有多种不同的形式

var functionName = function(arg0, arg1, arg2){// 函数体
}

上面语句,用话语表示,创建一个函数,把它赋值给一个变量,这个函数,我们叫做匿名函数,因为没有函数名称,在关键字function后面是没有标识符的,匿名函数的name值,获取的结果为空字符串。

注意,函数表达式和其他表达式是一样的,需要在使用前必须赋值,否则:

// 调用
da();
var da = function() {console.log('dada');
}

函数声明和函数表达式区别,关键就是在函数提升

// 函数表达式
var dada;
if(name) {dada = function() {console.log('da1');};
}else{dada = function() {console.log('da2');};
}

递归函数

什么是递归函数,就是一个函数通过名字调用自身。

function da(num) {if(num < 5) {return 'da';}else {return num * da(num-2);}
}

闭包

闭包就是可以访问 另一个函数中的变量的 函数,创建闭包即是在一个函数内创建另一个函数。

JavaScript 闭包

JavaScript 变量可以是局部变量或全局变量。私有变量可以用到闭包。

闭包就是能够读取其他函数内部变量的函数。

例如在javascript中,只有函数内部的子函数才能读取局部变量,所以闭包可以理解成“定义在一个函数内部的函数“。

在本质上,闭包是将函数内部和函数外部连接起来的桥梁。

闭包 (closure)是个精确但又很难解释的电脑名词。

在 Perl 里面,闭包是以 匿名函数的形式来实现,具有持续参照位于该函数范围之外的文字式变数值的能力。这些外部的文字变数会神奇地保留它们在闭包函数最初定义时的值 (深连结)。

在Javascript中闭包的创建过程

function a(){var i=0;function b(){alert(  i);}return b;
}
var c=a();
c();

1、函数b嵌套在函数a内部;2、函数a返回函数b。

面试官问我:什么是闭包,我该如何回答?

简单讲,就是指有权访问另一个函数作用域中的变量的函数。

它由两部分构成:函数,以及创建该函数的环境。环境由闭包创建时在作用域中的任何局部变量组成。

内存泄漏

闭包会引用包含函数的整个变量对象,如果闭包的作用域链中保存着一个HTML元素,那么就意味着该元素无法被销毁。我们有必要在对这个元素操作完之后主动销毁。

function da() {var element = document.getElementById('nameDa');var id = element.id;element.onclick = function() {console.log(id);};element = null;
}

函数内部的定时器

当函数内部的定时器引用了外部函数的变量对象时,该变量对象不会被销毁。

(function() { var da = 0;setInterval(function() {console.log(da  );},1000);
})();

运用闭包的过程

闭包引用外部函数变量对象中的值,在外部函数的外部调用闭包。

求和的函数是这样定义的:

function sum(arr) {return arr.reduce(function (x, y) {return x   y;});
}sum([1, 2, 3, 4, 5]); // 15

函数表示:

function lazy_sum(arr) {var sum = function () {return arr.reduce(function (x, y) {return x   y;});}return sum;
}var f = lazy_sum([1, 2, 3, 4, 5]); // function sum()f(); // 15

闭包特点:

让外部访问函数内部变量成为可能;
局部变量会常驻在内存中;
可以避免使用全局变量,防止全局变量污染;
会造成内存泄漏(有一块内存空间被长期占用,而不被释放)

每个执行环境都有一个表示变量的对象,变量对象,一般作用域链中包含两个变量对象,本地活动对象和全局变量对象,作用域链的本质就是一个指向变量对象的指针列表,它只引用但不实际包含变量对象。

在函数中访问一个变量时,会从作用域链搜索具有相同的名字的变量,一般地,当函数执行完成后,局部活动对象就会被销毁,内存中保存全局作用域。

一个内部函数会将它的外部函数的活动对象添加到它的作用域链中。闭包会带着它的函数的作用域,会占用更多的内存,多度使用闭包会导致内存占用过多。

函数表达式可以不用命名,就可以实现动态编程,函数表达式不需要名称,函数声明要求要有名字,没有名字的函数表达式叫做匿名函数,递归函数使用arguments.callee来递归地调用自身。

闭包的作用域链包含着自己的作用域,包含函数的作用域和全局作用域,一般,函数的执行后会被销毁,但是,函数返回一个闭包,这个函数的作用域将会一直在内存中保存到闭包不存在为止。

模块模式是为单例创建私有变量和特权方法。单例就是只有一个实例的对象,是以对象字面量的方法创建单例对象。

var da = {name: 'dada',eat: function() {// 代码}
};

私有建立和私有函数

var singleton = function(){ //私有变量和私有函数var privateVariable = 10; function privateFunction(){ return false; }//特权/公有方法和属性return { publicProperty: true, publicMethod : function(){ privateVariable  ; return privateFunction(); } };
}();
var application = function(){ //私有变量和函数var components = new Array(); //初始化components.push(new BaseComponent()); //公共return { getComponentCount : function(){ return components.length; }, registerComponent : function(component){ if (typeof component == "object"){ components.push(component); } } };
}();
var singleton = function(){ //私有变量和私有函数var privateVariable = 10; function privateFunction(){ return false; } //创建对象var object = new CustomType(); //添加特权/公有属性和方法object.publicProperty = true; object.publicMethod = function(){ privateVariable  ; return privateFunction(); }; //返回这个对象return object;
}();

var application = function(){ //私有变量和函数var components = new Array(); //初始化components.push(new BaseComponent()); //创建 application 的一个局部副本var app = new BaseComponent(); //公共接口app.getComponentCount = function(){ return components.length; }; app.registerComponent = function(component){ if (typeof component == "object"){ components.push(component); } }; return app;
}();

模仿块级作用域

function outputNumbers(count){ for (var i=0; i < count; i  ){ alert(i); } alert(i); //计数
}
function outputNumbers(count){ for (var i=0; i < count; i  ){ alert(i); } var i; //重新声明变量alert(i); //计数
}

闭包包含的是整个变量对象

function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i  ){ result[i] = function(){ return i; }; } return result;
}
function createFunctions(){ var result = new Array(); for (var i=0; i < 10; i  ){ result[i] = function(num){ return function(){ return num; }; }(i);} return result;
}

this

this,在全局函数中,this等价于window,当函数被作为某个对象的方法调用时,this等价于那个对象。

var name = "The Window";
var object = { name : "My Object", getNameFunc : function(){ return function(){ return this.name; }; }
};
alert(object.getNameFunc()());
//"The Window"(在非严格模式下)

任何在函数中定义的变量,都可以认为是私有变量,因不能在函数的外部访问这些变量。

私有变量包含函数的参数,局部变量和函数内部定义的其他函数。

function add(num1, num2){ var sum = num1   num2; return sum;
}
function MyObject(){ //私有变量和私有函数var privateVariable = 10; function privateFunction(){ return false; } //特权方法this.publicMethod = function (){ privateVariable  ; return privateFunction(); };
}
function Person(name){ this.getName = function(){ return name; }; this.setName = function (value) { name = value; };
}
var person = new Person("dada");
alert(person.getName()); //"dada"
person.setName("da");
alert(person.getName()); //"da"

静态私有变量

(function(){ //私有变量和私有函数var privateVariable = 10; function privateFunction(){ return false; } //构造函数MyObject = function(){ }; //公有/特权方法MyObject.prototype.publicMethod = function(){ privateVariable  ; return privateFunction(); };
})();

JavaScript this 关键字

面向对象语言中 this 表示当前对象的一个引用。

但在 JavaScript 中 this 不是固定不变的,它会随着执行环境的改变而改变。

在方法中,this 表示该方法所属的对象。如果单独使用,this 表示全局对象。在函数中,this 表示全局对象。在函数中,在严格模式下,this 是未定义的(undefined)。在事件中,this 表示接收事件的元素。类似 call() 和 apply() 方法可以将 this 引用到任何对象。

this 总是返回一个对象,简单说,就是返回属性或方法“当前”所在的对象。

this.property上面代码中, this 就代表 property 属性当前所在的对象。

var obj = {foo: function () {}
};var foo = obj.foo;// 写法一
obj.foo()// 写法二
foo()

虽然obj.foo和foo指向同一个函数,但是执行结果可能不一样

var obj = {foo: function () { console.log(this.bar) },bar: 1
};var foo = obj.foo;
var bar = 2;obj.foo() // 1
foo() // 2

var obj = { foo:  5 };

变量obj是一个地址(reference)。后面如果要读取obj.foo,引擎先从obj拿到内存地址,然后再从该地址读出原始的对象,返回它的foo属性。

http://www.ruanyifeng.com/blog/2018/06/javascript-this.html

在博客平台里,未来的路还很长,也希望自己以后的文章大家能多多支持,多多批评指正,我们一起进步,一起走花路。

非常感谢读者能看到这里,如果这个文章写得还不错,觉得「达达」我有点东西的话,觉得我能够坚持的学习,觉得此人可以交朋友的话, 求点赞

一篇文章带你了解JavaScript中的函数表达式,递归,闭包,变量,this对象,模块作用域相关推荐

  1. 一篇文章带你了解JavaScript中的面向 “对象”

    作者 | Jeskson 来源 | 达达前端小酒馆 安装webpack,打包工具,安装webpack-dev-server,安装babel解析es6语法,初始化npm环境. npm install w ...

  2. JavaScript中的函数表达式

    在JavaScript中,函数是个非常重要的对象,函数通常有三种表现形式:函数声明,函数表达式和函数构造器创建的函数. 本文中主要看看函数表达式及其相关的知识点. 函数表达式 首先,看看函数表达式的表 ...

  3. 一篇文章带你解决 SpringBoot 中 favicon 失效,不显示问题

    文章目录 一.常规思路 二.其他思路 一.常规思路 正常显示我们已经知道:一篇文章带你搞定 SpringBoot 自定义欢迎页和网页图标 favicon 如果正常设置不好使常规的思路是: (1)旧版的 ...

  4. 带你学习Javascript中的函数进阶(一)

    文章目录 1. 函数的定义和调用 1.1 函数的定义方式 1.2 函数的调用方式 2. this 2.1 函数内this的指向 2.2 改变函数内部this指向 2.3 call apply bind ...

  5. 一篇文章带你了解Python中的游戏开发模块pyglet

    前言 为什么我不选择pygame,原因很简单,因为pyglet 更简单,比较轻量级,就好比django和flask的区别. 相信你在读了这篇文章之后也会毅然决然地选择pyglet. 这篇文章主要围绕p ...

  6. 【一篇文章带你掌握HTML中ul、ol和dl列表的使用 - 超详细】

    前提 在项目开发过程中,列表是非常常见的,因此列表标签也是我们使用相对频繁的标签,但是当我们遇到列表的时候有没有停顿思考一下,我在这里应该使用html中的哪个列表标签才合理呢?    其实结合css样 ...

  7. JavaScript是什么?能做什么?一篇文章带你了解JavaScript的发展史、组成及作用

    JavaScript是什么?能做什么? JavaScript(简称JS)是当前非常流行.应用很广泛的脚本语言, JavaScript 是 web 开发者必学的三种语言之一 js的主要特点是: 一.js ...

  8. 一篇文章带你学会 Spring 中的 JdbcTemplate 增删改查操作

    文章目录 一.JdbcTemplate 概述 二.配置数据源 三.bean.xml配置文件 四.JdbcTemplate简单示例 五.批量操作多条记录 一.JdbcTemplate 概述 它是 spr ...

  9. 一篇文章带你搞定Python返回函数

    一.什么是返回函数? 返回函数,简单的说就是返回值是一个函数. 返回的是函数,调用返回的函数的时候才会返回结果. 二.闭包 (以返回函数的形式实现) 相关参数和变量都保存在返回的函数中,这种称为&qu ...

最新文章

  1. spark1.4加载mysql数据 创建Dataframe及join操作连接方法问题
  2. 【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活 | 成功率最高 | 推荐使用 )
  3. idea快捷键生成返回类型_十三肝了2晚的《IDEA操作手册-终极秘籍》终于来了......
  4. 如何使用ZBrush和3DMAX雕刻一个百夫长?
  5. 前端浏览器兼容知识点整理
  6. 简单的对象定位与登录实例的简单操作
  7. JavaScript 几种简单的table切换
  8. 2018-2019-2 网络对抗技术 20165314 Exp7 网络欺诈防范
  9. java中的标记接口
  10. ZeroMQ(java)之负载均衡
  11. Learning to Segment Object Candidates
  12. 最全面的 Spring 学习笔记
  13. html5图标用什么格式转换,ico转png 怎么把ico格式转换成png格式
  14. gmap实现地图的旋转
  15. (三)、IText通过pdf模板生成pdf文件(可用做回执单等功能)
  16. qnap虚拟linux,QNAP进阶教程:威联通NAS 虚拟机教程 安装精简版win10、软路由、群晖NAS系统!...
  17. 如何有效的制定团队能力提升计划?
  18. PM 如何进行测试?
  19. Reasoning with Sarcasm by Reading In-between(MIARN 2018)论文笔记
  20. python基础知识整理一

热门文章

  1. 创新社叶筱静受邀主持清华经管区块链前沿探讨
  2. Chrome浏览器作为默认浏览器时点击超链接无法跳转到浏览器
  3. Error: No such keg: /usr/local/Cellar/node安装nvmbrew安装Oh my zsh. git安装git设置别名No bundle URL prese
  4. Linux命令:dnsmasq
  5. 双调排序(Bitonic sort)学习
  6. 招远西苑学校计算机老师王梅,招远市西苑学校二位教师
  7. 开源IM-免费企业即时通讯-恩布互联ENTBOOST 1.4发布,增加管理中心
  8. Uncaught TypeError: $(...).size is not a function FastAdmin中使用bower的报错
  9. 笔记-2010-2011 孙薇薇
  10. 许广彬:数字化转型成为发展新引擎