一、JavaScript 闭包
闭包概述
基本描述:一个拥有许多变量和绑定了这些变量的环境的表达式(通常是一个函数),因而这些变量也是该表达式的一部分。
相关理论:
(1)JavaScript语言允许使用内部函数,即允许在一个函数内部进行另外一个函数的声明。
- function func1 () {
- function func2 () {}
- }
(2)JavaScript语言允许存在链式作用域(chain scope),即在一个函数内部声明另外一个函数,内层函数可以直接访问外层函数中声明的所有局部变量、参数和声明的其他内部函数。
- function func1 () {
- var temp = 1;
- function func2 () {
- console.log(temp);
- }
- }
相关语法:
因为闭包并没有绝对统一的语法,因此我们采用较为简单的形式来对闭包进行展示,为避免引起歧义,在此郑重声明:闭包绝对不等于匿名函数,闭包是一种代码编译器技巧,其作用是能够使得内部函数能够访问上级函数的内容。
闭包实例
在JavaScript世界中,函数外部无法【直接访问】函数内部的局部变量,这是不容否定的。但凡是总有例外,在实际开发过程中总是有这样或者那样的原因,使得开发者不得不在函数外部对函数内部的局部变量进行操作。这就需要用到闭包的技巧。
在上面的代码中,可以明确看到,在func2内部由于chain scope的存在,可以对局部变量temp进行直接访问,还记得之前提到过的一个名为【一等公民】的概念,两者结合,闭包结构便新鲜出炉。
- function func1 () {
- var temp = 1;
- return function () {
- console.log(temp);
- };
- }
闭包作用
基本描述:闭包的作用在实际开发中不可估量,其作用也并不是三言两语就能够完全交代清楚。其很多价值的体现都必须结合实际开发中的某种具体情况才能说明,但无论如何,其作用主要体现在以下两个方面上:
(1)闭包结构,允许函数外部对函数内部的局部变量、形式参数进行直接读取。
(2)闭包结构,能够使得局部变量所占内存始终不被回收。
- function func1 () {
- var temp = 1;
- return function () {
- temp ++;
- console.log(temp);
- };
- }
- var tempFunc = func1();
- tempFunc(); // 2
- tempFunc(); // 3
二、JavaScript 匿名函数
匿名函数
相关说明:实际上在JavaScript世界中并没有必要单独将【匿名函数】提炼出来作为单一的知识点来说。因为匿名函数根本算不得是具有某种特征的函数分类,而最多只能算是函数写法中的一种而已。
基本描述:在声明的过程中没有显式的写出函数名的时候,将其统称为匿名函数。
语法结构:function () {}
注意事项:
(1)单独书写匿名函数本身并无任何实际意义,通常匿名函数都会配合其他的写法来达到不同的目的。
- 1 var func1 = function () {}; //
- 2 return function () {};
- 3 (function () {})();
(2)建议:匿名函数只是一个习惯上的叫法,并不用过多的放在心上。与闭包相比,匿名函数可以认为是一个可有可无的称为,可以当作是为了和别人沟通而学习到的一个新的专业名词。
三、JavaScript 自执行函数
自执行函数
基本描述:自执行函数,全称为立即自动执行的函数结构表达式(immediately-invoked-function-express),简称IIFE。
语法结构:(function (形参) {} )(实参); / (function (形参) {} (实参));
存在目的:
(1)自执行函数不必主动调用,在声明的时候就能立即执行,有利于某些常见的信号量绑定操作。
(2)分割命名空间,避免对全局变量的命名污染。
注:闭包closure ≠ 匿名函数 ≠ 自执行函数IIFE
四、JavaScript 关键字this
关键字this
基本描述:this是JavaScript中提出的,一个用来表示其真正调用者的关键字,一般习惯在函数中使用,用来表示函数的真正调用者。
注意事项:this关键字所代表的内容是动态存在的,根据使用的位置不同将会表现为不同的值。也正因为上述原因,this是无法被确定描述为对象、属性或函数的。
表现形式:
(1)this在正常函数中:// 指向函数的调用者
(2)this在闭包中: // 指向window
(3)this在间隔调用和延迟调用函数中: // 指向window
(4)this在自执行函数中: // 指向window
(5)this在事件监听中:
在HTML级事件监听:指向window
在DOM0级事件监听:指向函数的调用者(监听绑定的节点)
在DOM2级事件监听:(IE)指向window (非IE) 指向函数的调用者(监听绑定的节点)
五、JavaScript 变更this指向
变更this指向:概述
相关说明:如果说this是用来表示【其真正调用者】的一个引用,由系统自动指定this所引用的内容的话,对this关键字的操作方法就必然存在,因为实际开发中this并不如我们想的那么好用。
相关方法:
(1)函数执行结果 = 调用函数.call(函数内this的值, 调用函数可能参数1,调用函数可能参数2,...);
(2)函数执行结果 = 调用函数.apply(函数内this的值,[调用函数可能参数1, 调用函数可能参数2,...]);
(3)新的函数 = 调用函数.bind(函数内的this值,调用函数可能参数1, 调用函数可能参数2,...);
注意事项:
(1)call和apply方法,会在改变函数内this指向的同时直接执行函数,而bind方法则会将变更后的函数以一个新函数的结果返回。
(2)call、apply还有bind方法的第一个参数是必要参数,如果写null则代表window对象。
总结:
call、apply和bind这三个函数的第一个参数都代表了函数调用时this指向的对象,差别主要体现在后面的参数上。call的参数是直接放进去的,第二第三第n个参数全都用逗号分隔,直接放到后面;apply的所有参数都必须放在一个数组里面传进去;bind除了返回的是函数以外,它的语法和call一样。三者的参数不限定是String类型,允许是其他各种数据类型。
变更this指向:扩展
事实上变更this指向的方法绝不仅仅只有上面的一种基本用法。下面简单介绍其中两种有关它们的扩展技巧。
(1)对系统提供的类进行方法的扩展
描述:通俗来讲,就是让没有某个方法的对象去调用这个“它本不拥有”的方法。
例子:让arguments集合对象调用数组的slice方法,进而将其本身由【类数组】转变为【真正的数组】
- function fun () {
- var arrSlice = Array.prototype.slice;
- var mySlice = Function.prototype.call.bind(arrSlice);
- return mySlice(arguments);
- }
- console.log(fun(1,2,3,4)); // [1,2,3,4]
(2)挑选数组中最大值
- Math.max.apply(null, [2,3,4,1,6,2,9]); // 9