js高级03变量提升、闭包(2)


变量提升机制
1.数据值操作机制

2.变量提升机制
+什么是变量提升
+带var和不带的区别
+等号左边变量提升
+条件判断下的变量提升
+重名问题的处理

3.ES6中let不存在变量提升
+不允许重复定义
+暂时性死区
+不存在变量提升

6.条件判断下的变量提升

在当前作用域下,不管条件是否成立都要进行变量提升

=>带var的还是只声明
=>带function的在老版本浏览器渲染机制下,声明+定义都处理。
但是为了迎合ES6中的块级作用域,新版浏览器对于函数(在条件判断中的函数),不管条件是否成立,都只是先声明,没有定义,类似于var。

 console.log(a);//undefined
 if (1 === 2) {  不成立,则不执行
     var a = 12;
 }
 console.log(a);//undefined

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
-条件判断下的变量提升到底有多坑(???)

函数本身:当条件成立,进入到判断体中(在ES6中它是一个块级作用域)

console.log(fn);  //undefined

if (1 === 1) {
    console.log(fn); ?//ƒ fn() {console.log('hello');}?
函数本身:当条件成立,进入到判断体中(在ES6中它是一个块级作用域)
第一件事并不是代码执行,而是类似于变量提升一样,先把fn声明和定义
了,也就是判断体中代码执行之前,fn就已经赋值了


    function fn() {
        console.log('hello');
    }
}
console.log(fn);//ƒ fn() {console.log('hello');}

7.重名问题的处理

//1.带var和function关键字声明相同的名字,这种也算是重名了(其实是一个fn,只是存储值的类型不一样)
//2.关于重名的处理:如果名字重复了,不会重新的声明,但是会重新的定义(重新赋值)

var fn = 11;
function fn() {
    console.log(22);

}
console.log(fn);//11
fn();//Uncaught TypeError: fn is not a function

????我也很懵????

  fn(); //undefined
  function fn() { console.log(1); }
  fn();  //4
  function fn() { console.log(2); }
  fn();  //4
  var fn = 100;
  fn();  //fn is not a function
  function fn() { console.log(3); }
  fn();  //fn is not a function
  function fn() { console.log(4); }
  fn();  //fn is not a function

3.ES6中let不存在变量提升

3.1不允许重复定义

3.2不存在变量提升

1.在ES6中基于let/const等方式创建变量或者函数,不存
在变量提升机制,(存在作用域链)

2.切断了全局变量和w工NDOW属性的映射机制

=>在相同的作用域中,基于LET不能声明相同名字的变量(不管用什么方式在当前作用域下声明了变量,再次使用LET创建都会报错)

虽然没有变量提升机制,但是在当前作用域代码自上而下执行之前,浏览器会做一个重复性检测(语法检测):自上而下查找当前作用域下所有变量,一旦发现有重复的,直接抛出异常,代码也不会在执行了(虽然没有把变量提前声明定义,但是浏览器已经记住了,当前作用域下有哪些变量)

console.log(a); // Uncaught ReferenceError: Cannot access 'a' before initialization

let a = 12;
console.log(window.a);//undefined
let a = 12, b = 10;
let fn = function () {
    //console.log(a, b);//Uncaught ReferenceError: Cannot access 'a' before initialization
    let a = b = 20;  //let a=20;  把全局中的b=20
    console.log(a, b);//20  20
}
fn();
console.log(a, b);//10 20

3.3暂时性死区(??)

// var a = 12;
// if (true) {
//     console.log(a);//=>Uncaught ReferenceError: a is not defined
//     let a = 13;//=>基于LET创建变量,会把大部分{}当做一个私有的块级作用域(类似于函数的私有作用域),在这里也是重新检测语法规范,看一下是否是基于新语法创建的变量,如果是按照新语法规范来解析
// }



// console.log(a);//=>Uncaught ReferenceError: a is not defined
console.log(typeof a);//=>"undefined" 在原有浏览器渲染机制下,基于typeof等逻辑运算符检测一个未被声明过的变量,不会报错,返回UNDEFINED


// console.log(a);//=>Uncaught ReferenceError: a is not defined
console.log(typeof a);//=>Uncaught ReferenceError: a is not defined
let a;//=>如果当前变量是基于ES6语法处理,在没有声明这个变量的时候,使用TYPEOF检测会直接报错,不会是UNDEFINED,解决了原有的JS的死区

-------------------------------------------------------------------------------------------------------------------------------------------------------------

·闭包作用域(scope)
1.作用域处理机制
+全局变量和私有变量
+作用域链机制
+闭包的作用:保存&保护

2.闭包作用域练习
+JQ源码分析
+选项卡剖析
+面试题练习

3.ES6中的块级作用域
+let可以形成块级作用域
+实际意义
+const

闭包、作用域(scope)

1.作用域处理机制

闭包:形成私有作用域保护变量不受外界的干扰,这种保护机制可以理解为闭包。私有作用域下的数据和全局的无关

作用域:函数执行会形成一个私有作用域,给代码执行提供一个环境

1.1全局变量和私有变量

在全局作用域下声明的变量是全局变量,
在私有作用域下声明的变量是私有变量。

var a = 123;
if (true) {
    a = 321;// Cannot access 'a' before initialization
    let a = 888;
}

var a = 12, b = 13, c = 14;
function fn(a) {
    console.log(a, b, c);//12  undefined  14(C是全局的)
    var b = c = a = 20;
    /*var b=20;   c=20;把全局的c修改为20   a=20;*/

    console.log(a, b, c); // 20  20  20 
}
fn(a);
/*把FN执行(小括号中是实参:值)
执行FN把全局变量A的值12当做实参传递给函数的形参
fn (12)
*/
console.log(a, b, c);//12  13  20

-------------------------------------------------------------------------------------------------------------------
8-关于私有变量的一点练习

var ary = [12, 23];
function fn(ary) {
    console.log(ary);   //[12, 23]
    ary[0] = 100;
    ary = [100];
    ary[0] = 0;
    console.log(ary);    //[0]
}
fn(ary);
console.log(ary);  //[100,23]

在这里插入图片描述

1.2作用域链机制

上级作用域的查找

 var a = 12;
 function fn() {
     console.log(a);
 }
 fn();//12
 var a = 12;
 function fn() {
     console.log(a);
 }
 function sum() {
     var a = 120;
     fn();   fn函数是在全局下创建的,他要向上查找到  a = 12;
 }
 sum();//12

当前函数执行,形成一个私有作用域A,A的上级作用域是谁,和他在哪执行的没有关系。
和他在哪创建(定义)的有关系,在哪创建的,它的上级作用域就是谁。

var a = 12;
function fn() {
     
    // arguments:实参集合
    
    // 了解 arguments.callee:函数本身fn
    // 了解 arquments.callee.caller:当前函数在哪执行的,CALLER就是谁(记录的是它?执行的宿主环境),在全局下执行caller的结果是null
    console.log(arguments.callee.caller);
}
function sum() {
    var a = 120;
    fn();
}
sum();// sum() { var a = 120;  fn();     }

function aa(){  
    fn();
}
aa();//ƒ aa(){ fn(); }
 var n = 10;
 function fn() {
     var n = 20;
     function f() {
         n++;
         console.log(n);
     }
     f();
     return f;
 }

 var x = fn();  //21
 x();//22
 x();//23
 console.log(n);//10

在这里插入图片描述

堆栈内存

JS中的内存分为堆内存和栈内存

  • 堆内存:存储引用数据类型值(对象:键值对 函数:代码字符串)
  • 栈内存:提供JS代码执行的环境和存储基本类型

-----------------------------------------------------------------------------------------

[堆内存释放]

  • 让所有引用堆内存空间地址的变量赋值为null即可(没有变量占用这个堆内存了,浏览器会在空闲的时候把它释放掉)

[栈内存释放]

  • 一般情况下,当函数执行完成,所形成的私有作用域(栈内存)都会自动释放掉(在栈内存中存储的值也都会释放掉),但是也有特殊不销毁的情况:
  • 1.函数执行完成,当前形成的栈内存中,某些内容被栈内存以外的变量占用了,此时栈内存不能释放(一旦释放外面找不到原有的内容了)
  • 2.全局栈内存只有在页面关闭的时候才会被释放掉
  • 如果当前栈内存没有被释放,那么之前在栈内存中存储的基本值也不会被释放,能够一直保存下来

???


        var i = 1;
        function fn(i) {
            return function (n) {
                console.log(n + (++i));
            }
        }
        var f = fn(2); 
        f(3);       6
        fn(5)(6);   12
        fn(7)(8);   16
        f(4);       8

1.3闭包的作用:保存&保护

[闭包]

  • =>函数执形成一个私有的作用域,保护里面的私有变量不受外界的干扰,这种保护机制称之为“闭包”

  • =>市面上的开发者认为的闭包是:形成一个不销毁的私有作用域(私有栈内存)才是闭包

柯里化函数
    function fn() {
        return function () {
        }
    }
    var f = fn();

惰性函数
    var utils = (function () {
        return {
        }
    })();

/闭包项目实战应用
真实项目中为了保证Js的性能(堆栈内存的性能优化),应该尽可能的减少闭包的使用(不销毁的堆栈内存是耗性能的)

1.闭包具有”保护”作用:保护私有变量不受外界的干扰
2.闭包具有"保存”作用:形成不销毁的栈内存,把一些值保存下来,方便后面的调取使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值