一、函数对象隐含属性
函数声明,就相当于创建函数对象。函数对象中有以下隐含属性: 1、arguments 1) 在调用函数时,对函数数据预处理阶段进行初始化。 arguments赋值为实参列表,并将其添加为执行上下文对象的属性。 2) 函数调用时以及调用完毕,arguments会自动初始化为undefined。 2、this 1) this从广义上来说是函数对象隐藏的属性, 但是实质上this是执行上下文对象的属性,而不是函数的属性。 2) 调用函数时,对函数数据预处理阶段初始化。 this属性赋值为调用函数的对象。 3、__proto__(显示原型) 1) 默认指向构造函数隐式原型执行的原型对象,即Function.prototype 4、prototype(隐式原型) 1) 默认指向构造函数隐式原型执行的原型对象,即Function.prototype 5、 [[Scopes]](作用域链属性) 1) 外部不能访问,只供JS引擎访问。 2) 作用域链在函数编码时就已经确定。 作用域链是抽象的概念,而作用域链属性是作用域链具体的代码实现。 3) 作用域链属性是个数组。从索引值0开始查找。 默认情况下,在函数声明,即函数对象创建时,索引值0 指向window对象。 在闭环函数中,
讯享网
1.1 函数对象隐含属性
1)arguments、proto、prototype、[[Scopes]] 是函数对象隐含的属性
讯享网 function s(){
var h="!23"; } console.dir(s)
2)[[Scopes]] 也是是函数对象隐含的属性。但是只给JS引擎访问。
function sss(){
var s=12; console.log("123") } console.log("arguments" in sss) console.log("prototype" in sss) console.log("__proto__" in sss) console.log("[[Scopes]]" in sss)

3)this从广义上来说是函数对象隐含的属性,但是实质上this是函数对象对应的执行上下文对象的属性
讯享网 function sss(){
var s=12; console.log("123") } console.log("arguments" in sss) //true console.log("prototype" in sss) //true console.log("__proto__" in sss) //true console.log("this" in sss) //false

1.2 arguments属性
1)arguments属性在函数调用时,执行函数体代码前进行初始化的
2)arguments属性在函数调用完毕会自动初始化为null
function sss(){
console.log(arguments) } console.log(sss.arguments) sss("123"); console.log(sss.arguments)

1.3 [[Scopes]] 属性( 闭包之 [[Scopes]] 属性 )
讯享网 作用域链是一个抽象的概念,在函数硬编码阶段,作用域链就已经确定。 作用域链属性是作用域链这个抽象概念的代码实现。
二、闭包
+++ 闭包的由来 1、函数执行完毕,函数内部的变量就会被释放。 但是由于闭包,延长了闭包函数引用外部函数的变量的存储时间。 2、函数作用域是独立的、封闭的,外部的执行环境是访问不了的。 但是由于闭包,函数可以访问另外一个函数作用域的变量。 +++ 闭包 1) 从狭义上来说,闭包就是能够读取其他函数内部变量的函数。 函数嵌套,内部函数引用了外部函数的变量,则该内部函数叫做闭包函数。 2) 从广义上来说。闭包就是闭包作用域对象。它只保存闭包函数引用外部函数的变量。 该对象被闭包函数的作用域链属性所引用。 +++ 产生闭包的条件 1) 函数嵌套 2) 内部函数引用了外部函数中的数据。 3) 执行外部函数。 即闭包函数被声明,闭包函数对象被创建。 +++ 闭包的声明周期 闭包函数定义执行,就会创建闭包。 闭包创建后,闭包函数不被外部引用,就会死亡。 +++ 闭包的作用 1、延长了函数局部变量的生命周期。 使函数内部的变量在函数执行完毕后,仍然存活在内存中。 2、在函数外部可以直接操作到函数内部的数据。
1.1 闭包
1)创建闭包的条件
>>>>>> 内部函数必须引用外部函数的变量,才会创建闭包作用域对象
内部函数没有引用外部函数的变量则不会创建闭包作用域对象
讯享网 function s(){
var a=12; function ss(){
console.log("123") } return ss; } var h=s(); h();

内部函数引用了外部函数的变量才会创建闭包作用域对象
function s(){
var a=12; function ss(){
a++; console.log("123") } return ss; } var h=s(); h();

>>>>>> 闭包函数定义执行,才会创建闭包
2)闭包的生命周期
讯享网 闭包的生命周期: 产生: 闭包函数定义执行,就会创建闭包。 死亡: 闭包函数对象不被外部引用就会死亡。
>>>>>> 闭包函数定义执行时,才会创建闭包
function ff(){
//在执行该行代码时,就已经产生了闭包。 var a=1; function f(){
a++; console.log(a) } return f; } var f=ff();
在调用ff函数后,首先会初始化ff函数数据,
由于变量提升与函数提升。变量a与变量f会被提升,但是f的初始化没有被提升。
所以在执行f的初始化时,才会创建闭包。
讯享网 function ff(){
var a=1; //在执行该行代码时,才会产生闭包。 var f=function (){
a++; console.log(a) } return f; } var f=ff();
>>>>>> 闭包函数对象不会外部引用,就会死亡
function ff(){
//在执行该行代码时,就已经产生了闭包。 var a=1; function f(){
a++; console.log(a) } return f; } var f=ff(); f(); //设置f为null。此时闭包函数不被外界访问,成为垃圾对象 //此时闭包就会死亡。 f=null;
3)闭包的作用
讯享网 闭包的作用: 1、延长了函数局部变量的生命周期。 使函数内部的变量在函数执行完毕后,仍然存活在内存中。 2、在函数外部可以直接操作到函数内部的数据。
>>>>>> 闭包的由来
function s(){
var a=12; console.log(a++) } //函数在调用后,其内部定义的变量就会被释放 s(); //外部不能访问函数内部变量 console.log(a);//报错
>>>>>> 闭包的作用
讯享网 function s(){
var a=12; function ss(){
a++; console.log(a); } return ss; } var h=s(); h(); h();

1.2 闭包的应用
1)利用闭包定义JS模块
1、JS模块是具有特定功能的JS文件。 2、所有的数据和函数封装到一个函数中。 3、只向外暴露一个具有包含n个方法的对象。
>>>>>> 方式一
index.js
讯享网 function myModel(){
var msg="abc" function doSomething(){
console.log(msg.toUpperCase()) } function doSomething2(){
console.log(msg.toLocaleLowerCase()) } return {
"doSomething":doSomething, "doSomething2":doSomething2 } }
index.html

<script type="text/javascript" src="a.js" ></script> <script> var model=myModel(); model.doSomething(); model.doSomething2(); </script>

>>>>>> 方式二(典型封装)
index.js
讯享网 (function(){
var msg="abc" function doSomething(){
console.log(msg.toUpperCase()) } function doSomething2(){
console.log(msg.toLocaleLowerCase()) } //向外暴露 window.myModel={
"doSomething":doSomething, "doSomething2":doSomething2 } })();
index.html
<script type="text/javascript" src="a.js" ></script> <script> myModel.doSomething(); myModel.doSomething2(); </script>

3)利用闭包循环添加监听事件
>>>>>> 方式一:普通添加
讯享网 var divs=document.getElementsByTagName("div"); for(var i=0;i<divs.length;i++){
divs[i].index=i; divs[i].onclick=function(){
console.log("这是第"+this.index+"个按钮") } }
>>>>>> 方式二:利用闭包来实现
var divs=document.getElementsByTagName("div"); for(var i=0;i<divs.length;i++){
(function(i){
divs[i].onclick=function(){
console.log("这是第"+i+"个按钮") } })(i); }
1.3 作用域链属性 – [[Scopes]] 属性 【闭包的本质】
讯享网 1) 作用域链是一个抽象的概念,在函数硬编码阶段,作用域链就已经确定。 作用域链属性是作用域链的代码实现。在函数定义执行时确定。 2) 作用域链属性是内部属性,外部无法访问。只供JS内部调用。 3) 作用域链属性一个指向变量对象的指针列表,它只引用但不实际包含变量对象。 a、普通函数中作用域链属性只有一个全局执行上下文对象,即window对象。 b、闭包函数中作用域链属性从索引值0开始依次是闭包作用域对象、全局执行上下文。 1) 闭包作用域对象是我自己定义的概念。 闭包作用域对象存储的是闭包函数引用上一级函数的变量。 2) 闭包作用域对象只有在闭包函数引用外部函数变量时才会形成,否则不会。 4) 闭包作用域对象 a、闭包作用域对象是我自己定义的概念。 它只保存闭包函数引用的外部函数的变量。 b、闭包作用域对象只有在内部函数引用外部函数变量时才会形成。 5) 作用域链属性的作用: 查找变量时,首先在自身作用域对应的执行上下文对象中查找变量, 如果找不到,就到作用域链属性中从索引值0开始依次向上查找。
1)作用域链属性是函数的内部函数,只给JS引擎访问
function s(){
var h=12; } console.dir(s)

2)作用域链属性一个指向变量对象的指针列表
>>>>>> 普通函数的作用域链属性中只有一个window对象
讯享网 function s(){
var h=12; } console.dir(s)

>>>>>> 闭包函数的作用域链属性中从索引值0开始依次是闭包作用域对象、全局执行上下文。
function s(){
var h=12; function s2(){
h++; } return s2; } var m=s(); console.dir(m)

讯享网 function s(){
var h=12; function s2(){
var a=12; function s3(){
a++; h++; } return s3; } return s2(); } var m=s(); console.dir(m)

3)闭包作用域对象
>>>>>> 闭包作用域对象只保存闭包函数引用外部函数的变量,外部函数的其他变量不会保存。
function s(){
var h=12; var s=122; function s2(){
h++; } return s2; } var m=s(); console.dir(m)

>>>>>> 闭包作用域对象只在内部函数引用外部时才会创建。
讯享网 function s(){
var h=12; var s=122; function s2(){
console.log("!23") } return s2; } var m=s(); console.dir(m)

4)作用域链属性的作用
作用域链是在编码时就已经确定的,而作用域链属性是作用域链的代码实现。 查找变量: 1、沿着作用域链查找变量 查找变量时,首先在自身作用域对象的执行上下文对象查找, 找不到,就到函数的作用链属性中查找,从0开始依次查找。 2、沿着原型链查找对象的属性
1.5 常见的闭包
>>>>>> 将函数对象作为另外一个函数的返回值
讯享网 function ff(){
var a=1; function f(){
a++; console.log(a) } return f; } //创建了一个闭包函数,即产生一个闭包作用域对象 var f=ff(); f(); //2 f();//3 //又创建了一个闭包函数,即产生一个闭包作用域对象 var f2=ff(); f2();//2 f2();//3

>>>>>> 将函数作为实参传递给另一个函数调用
function showDelay(msg,time){
setTimeout(function(){
alert(msg) },time) } showDelay("213",2000)
1.6 闭包的缺点
讯享网 闭包的缺点: 闭包的作用就是延长了局部变量的生命周期。 但是如果闭包函数执行完,如果没有释放闭包函数,容易造成内存泄露。
function s(){
var a=new Array(10000); function ss(){
console.log(a.length) } return ss; } var h=s(); h(); h=null; //让闭包函数成为垃圾对象,被回收
三、内存泄露与内存溢出
讯享网 +++ 内存溢出与内存泄漏 内存溢出: 内存溢出是一种程序运行的错误。 当程序的运行内存超过剩余内存时,就会抛出内存溢出的报错。 内存泄露: 内存泄露是指占用的内存没有及时释放 内存泄露积累多了容易造成内存溢出。 内存泄露是量变,内存溢出是质变。 +++ 常见的内存泄露: 1) 意外的全局变量 2) 没有及时清理的定时器 3) 没有及时清理闭包函数
3.1 直视JS运行占用的内存
var obj={
}; for(var i=0;i<1000;i++){
obj[i]=new Array() } console.log(obj.length)
运行上述代码,查看内存,会发现内存一直向上飙升

3.2 内存泄露与内存溢出
1) 内存泄露是一种程序运行的错误

2) 内存溢出是指占用的内存没有及时释放
闭包函数在运行完后,没有及时释放,就会造成内存溢出
讯享网 function f(){
var a=1; function f2(){
a++; } return f2; } var h=f(); h();
3) 内存溢出与内存泄露的关系
内存溢出是量变,内存泄露是质变。 内存溢出积累多了,就会造成内存泄露。
3.3 常见的内存溢出(解决方案)
1)意外的全局变量
讯享网 //1.意外的全局变量 function s(){
a=new Array(10000) console.log(a.length) } //解决方案 // a=null;
2)没有及时清理定时器
//2.没有及时清理定时函数 var id=setInterval(function s(){
console.log("!23") },3000) //解决方案 // clearInterval(id)
3)没有及时清理闭包函数
讯享网 //3.闭包 function f(){
var a=1; function f2(){
a++; } return f2; } var h=f(); h(); //解决方案 // h=null;

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/20798.html