大佬教程收集整理的这篇文章主要介绍了详解JavaScript的闭包、IIFE、apply、函数与对象,大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。
1.1、闭包相关的问题
1.2、理解闭包
2.1、对象常量(字面量)
2.2、取值
2.3、枚举(遍历)
2.4、更新与添加
2.5、对象的原型
2.6、删除
2.7、封装
3.1、参数对象 (arguments)
3.2、构造函数
3.3、函数调用
3.3.1、call
3.3.2、apply
3.3.3、caller
3.3.4、Callee
3.5、立即执行函数表达式 (IIFE)
3.5.1、匿名函数与匿名对象
3.5.2、函数与函数表达式
3.5.3、立即执行函数表达式与匿名对象
3.5.4、各种IIFE的写法
3.5.5、参数
3.5.6、添加分号
3.5.7、IIFE的作用
3.5.8、IIFE的变形
请在页面中放10个div,每个div中放入字母a-j,当点击每一个div时显示索引号,如第1个div显示0,第10个显示9;方法:找到所有的div,for循环绑定事件。
示例代码:
运行结果:
因为点击事件的函数内部使用外部的变量i一直在变化,当我们指定click事件时并没有保存i的副本,这样做也是为了提高性能,但达不到我们的目的,我们要让他执行的上下文保存i的副本,这种机制就是闭包。
运行结果:
n是外部函数的值,但是内部函数(点击事件)需要使用,返回函数前的n被临时驻留在内存中给点击事件使用,简单说就是函数的执行上下文被保存起来,i生成了多个副本。
闭包概念:当一个内部函数被调用,就会形成闭包,闭包就是能够读取其他函数内部变量的函数,定义在一个函数内部的函,创建一个闭包环境,让返回的这个子程序抓住i,以便在后续执行时可以保持对这个i的引用。内部函数比外部函数有更长的生命周期;函数可以访问它被创建时所处的上下文环境。
Javascript语言特有的"链式作用域"结构(chain scope),子对象会一级一级地向上寻找所有父对象的变量
对象就是“键/值”对的集合并拥有一个连接到原型(prototype)对隐藏连接。
一个对象字面量就是包含在一对花括号中的零个或多个“键/值”对。对象字面量可以出现在任何允许表达式出现的地方。
对象的定义:
对象中可包含的内容:
对象常量可以出现在任何允许表达式出现的地方,对象、数组、函数可以相互间嵌套,形式可以多种多样。对象的值可以是:数组,函数,对象,基本数据类型等。
输出:大家好,我是lucy
方法二:使用索引器,当对象中的key有空格是
方法一:
运行结果:
输出顺序是不能保证的。
如果对象中存在属性就修改对应值,如果不存在就添加。对象通过引用传递,它们永远不会被复制
输出:
Queen,1000
//引用
var obj9=obj8; //obj9指向obj8的引用
obj9.realname="Jack";
obj8.show();
输出:
javascript是一种动态语言,与C#和Java这样的静态语言是不一样的;javascript并没有严格的类型,可以简单认为Javascript是由对象组成的,对象间连接到原型(prototype)实现功能的扩展与继承。每个对象都链接到一个原型对象,并且可以从中继承属性,所有通过常量(字面量)创建的对象都连接到Object.prototype,它是JavaScript中的顶级(标配)对象,类似高级语言中的根类。
现在我们修改系统中的Object对象,添加一个创建方法,指定要创建对象的原型,实现类似继承功能:
运行结果:
原型关系是一种动态关系,如果修改原型,该原型创建的对象会受到影响。
var jack=Object.create(rosE);
jack.name="jack";
//修改原型中的方法
rose.show=function(){
console.log("姓名->"+this.Name);
}
结果:
关于原型在函数中会再讲到。
删除不用的属性是一个好习惯,在某些情况下可能引发内存泄漏。
使用对象封装的好处是可以减少全局变量的污染机会,将属性,函数都隶属一个对象。
封装后:
运行结果:
javascript中的函数就是对象,对象就是“键/值”对的集合并拥有一个连接到原型对隐藏连接。
第一个函数中有一个默认对象叫arguments,类似数组,但不是数组,该对象是传递给函数的参数。
运行结果:
1205
0
这里的arguments是一个隐式对象,不声明也在函数中,内部函数可以访问外部函数的任意内容,但是不能直接访问外部函数的arguments与this对象。
运行结果:
3
0
在javascript中对象构造函数可以创建一个对象。
3.3.1、call
调用一个对象的一个方法,以另一个对象替换当前对象
call([thisObj[,args])
hisObj 可选项。将被用作当前对象的对象。args 将被传递方法参数序列。
call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 thisObj 指定的新对象。
示例:
运行结果:
call方法中的参数都可以省去,第1个参数表示在哪个对象上调用该方法,或this指向谁,如果不指定则会指向window对象。
示例:
结果:
undefined:无名,18
3.3.2、apply
apply([thisObj[,argArray]])
应用某一对象的一个方法,用另一个对象替换当前对象,与call类似。
如果 argArray 不是一个有效的数组或者不是arguments对象,那么将导致一个 TypeError。
如果没有提供 argArray 和 thisObj 任何一个参数,那么 Global 对象将被用作 thisObj, 并且无法被传递任何参数。
对于第一个参数意义都一样,但对第二个参数:
apply传入的是一个参数数组,也就是将多个参数组合成为一个数组传入,而call则作为call的参数传入(从第二个参数开始)。
如 func.call(func1,var1,var2,var3)对应的apply写法为:func.apply(func1,[var1,var3])
同时使用apply的好处是可以直接将当前函数的arguments对象作为apply的第二个参数传入
示例代码:
运行结果:
从上面的示例中可以发现apply的第2个参数是一个数组,数组中的内容将映射到被调用方法的参数中,如果单这样看发现不如call方便,其实如果直接取方法的参数arguments则apply要方便一些。通过简单的变化就可以替代call。
结果:
hi:jack,20,224cm
javascript里call和apply操作符可以随意改变this指向
如果在javascript语言里没有通过new(包括对象字面量定义)、call和apply改变函数的this指针,函数的this指针都是指向window的。
关于this指针,我的总结是:是谁调用的函数,那么这个函数中的this指针就是它;如果没有明确看出是谁调用的,那么应该就是window调用的,那么this指针就是window。
3.3.3、caller
在一个函数调用另一个函数时,被调用函数会自动生成一个caller属性,指向调用它的函数对象。如果该函数当前未被调用,或并非被其他函数调用,则caller为null。
在JavaScript的早期版本中,Function对象的caller属性是对调用当前函数的函数的引用
运行结果:
caller与this还是有区别的,this是指调用方法的对象,而caller是指调用函数的函数。
结果:
3.3.4、Callee
当函数被调用时,它的arguments.callee对象就会指向自身,也就是一个对自己的引用
运行结果:
当第1次调用add方法时输入3,立即将函数返回再次调用,每次调用后又返回自己,这样可以实现链式编程。
IIFE即Immediately-Invoked Function Expression,立即执行函数表达式
3.5.1、匿名函数与匿名对象
匿名函数就是没有名称的函数,javascript中经常会使用匿名函数实现事件绑定,回调,实现函数级的私有作用域,如下所示:
匿名对象:
没有名称的匿名函数也叫函数表达式,它们间是有区别的。
3.5.2、函数与函数表达式
下面是关于函数与函数表达式定义时的区别
a)、函数定义(Function Declaration)
function Identifier ( Parameters ){ FunctionBody }
function 函数名称(参数){函数主体}
在函数定义中,参数(Parameters)标识符(Identifier )是必不可少的。如果遗漏,会报提示错误:
代码:
结果:
b)、函数表达式(Function Expression)
function Identifier(Parameters){ FunctionBody }
函数表达式中,参数和标识符都是可选的,与函数定义的区别是标识符可省去。
其实,"function Identifier(Parameters){ FunctionBody }"并不是一个完整的函数表达式,完整的函数的表达式,需要一个赋值操作。
比如: var name=function Identifier(Parameters){ FunctionBody }
3.5.3、立即执行函数表达式与匿名对象
第3种写法为什么这样就能立即执行并且不报错呢?因为在javascript里,括号内部不能包含语句,当解析器对代码进行解释的时候,先碰到了(),然后碰到function关键字就会自动将()里面的代码识别为函数表达式而不是函数声明。
如果需要将函数表达式或匿名对象立即执行,可以使用如下方法: