美文网首页
js小知识点串讲

js小知识点串讲

作者: YM雨蒙 | 来源:发表于2017-10-12 22:48 被阅读20次

    变量的生命周期

    • 看几个小例子
    //问题一: a什么时候被赋值,或者a什么时候出现在内存中?什么时候消失?
    
    <script>
      var a = 1  //当代码执行到这一行时才有1
      // => window.a = 1   所以当页面关闭时a消失,或者刷新又有了新的a
    </script>
    
    //问题二:  a什么时候被赋值,或者a什么时候出现在内存中?什么时候消失?
    
    <script>
      function fn(){
        var a = 1    //当函数调用后a才出现
      }
      //浏览器执行到这一行
      fn()  //执行完成以后a消失
      // fn() 重新调用,重新赋值a
    </script>
    
    //问题三: 如果a被引用者,a什么时候被赋值,或者a什么时候出现在内存中?什么时候消失?
    
    <script>
      function fn(){
        var a = {name : 2}   //执行完不会消失,因为被引用,当window页面关闭,消失
        var b = 2  // 执行完就消失了,因为没有东西引用它
        window.f = a
      }
      fn()  
      console.log(window.f)  //1
      window.f = {name : 3}  //a没有被引用,消失
    </script>
    

    总结一下:

    • 默认作用域消失时,内存就被回收
    • 如果内存被引用着,则不能回收

    var 作用域

    • 就近原则
    • 词法作用域
    • 同名的不同变量

    一直觉得看例子最直接

    //问题一: a=1,指的是哪个a
    
    <script>
      var a
      function f1(){
        var a 
        function f2(){
          var a  //同一作用域级的a 就近原则
          a = 1
        }
      }
    //函数同理
      function f2(){}
      function f1(){
        function f2(){
          f2()  //指向父级f2
        }
      }
    </script>
    
    <script>
    //词法作用域 ,不同作用域的a是不同的变量
      var a
      function f1(){
        var a 
        function f2(){
          var a 
          f3()
          a = 1
        }
      }
      function f3(){
        a = 2 //指向第一个a
      }
    

    立即执行函数

    -想得到一个独立的作用域.声明一个函数

    fucntion f1(){
      var a
      a = 1
      console.log(a)
    }
    f1()
    =>
    //但是我想不想要全局变量f1怎么办啊,改一下
    function (){
      var a
      a = 1
    }()   //语法会报错?怎么办呢
    =>
    (function (){
      var a
      a = 1
    })()   
    或者
    !function (){
      var a
      a = 1
    }()   //需要的是一个独立的作用域
    
    函数前面可以加 + - ~ 都可以成为立即执行函数
    
    //立即执行函数可以加参数
    var a = 100
    !function (a){  //形参声明的变量,值是第一个参数
      var a = arguments[0]
      var a
      a = 1
    console.log(a)   //1
    }(/*没有参数*/)
    console.log(a)  //100 
    
    var a = 100
    !function (a){
      console.log(a)  //99 新的作用域
    }(99)
    
    //问题: 实参a 和形参a 是同一个a 吗?
    var a = 100
    !function (a){  //新声明的a,只是恰好名字相同,a可以是b,c,i,h不同的名字
      console.log(a) //100 赋值时var a =100
    }(a)  //这个a是var a = 100
    

    变量(声明)提升

    • 浏览器在执行代码之前,会先把所有声明提升到作用域的顶部
    • 你却从来不知道去提升一下变量
    • 只要你提升变量,面试题就是小 case

    就喜欢例子

    // 问题: a 的值是多少
    var a = 100
    function a(){}
    ==>
    var a
    function a(){}
    a = 100
    console.log(a)  // 100
    
    //问题: a 的值是什么
    var a = 100
    var a = function (){}
    function a(){}
    
    console.log(a)
    
    // 以下代码执行时,三次打印分别输出什么?为什么?手动提升作用域
     
    function add1(i){
      console.log("函数声明:"+(i+1));
    }
    add1(1);  // 101
     
    var add1 = function(i){
      console.log("函数表达式:"+(i+10));
    }
    add1(1);  // 11
     
    function add1(i) {
        console.log("函数声明:"+(i+100));
    }
    add1(1);  // 11
    

    时机(异步)

    button.onclick = function(){
      console.log("A") //当用户操作,才打印
    }
    console.log("B")  //先打印
    
    还有setTimeout
    

    复习了上面那么多只是,就是为了做一些面试题目:

    <ul>
      <li>选项1</li>
      <li>选项2</li>
      <li>选项3</li>
      <li>选项4</li>
      <li>选项5</li>
      <li>选项6</li>
    </ul>
    
    var items = document.querySelectorAll('li')
    
    for(var i=0; i<items.length; i++){
       items[i].onclick = function(){
         console.log(i)  //每次结果都是li的长度,为什么呢??
       }
    }
    
    ==>
    //提升一下变量,在观察
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      //i = 0,1,2,3,4,5,6
      items[i].onclick = function(){
        console.log(i)  //点击每一次打印都是6 怎么解决这个问题呢?
      }
    }
    console.log(i)  //6
    
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      //创建一个函数作用域
      var temp = function(j){
        console.log(j)
      }
      //把函数i作为参数传进去,得到的是6个不同的值
      temp(i)   //i = 0,1,2,3,4,5
    
      items[i].onclick = function(){
        console.log(i)
      }
    }
    
    ==> 再改一下
    
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      //创建一个函数作用域
      var temp = function(j){
        // j1 = 0, j2 = 1 ...
        console.log(j)
        items[j].onclick = function(){
          // 每点击一次,出现的值不同
          console.log(j)
        }
      }
      //把函数i作为参数传进去
      temp(i) 
    }
    
    ==>
    
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      //立即执行函数
     !function(j){
        items[j].onclick = function(){
          // 每点击一次,出现的值不同
          console.log(j)
        }
      //i作为参数传进去
      }(i)
    }
    

    另一种方法

    //修改一下上面
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      function temp(j){
        //return一个函数
        return function(){
          console.log(j)
        }
      }
      var fn = temp(i)  //创建一个新的作用域
      items[i].onclick = fn  //等于一个函数
    }
    
    ==>
    
    var items
    var i
    items = document.querySelectorAll('li')
    for(i=0; i<items.length; i++){
      items[i].onclick = function(i){
        //return一个函数
        return function(){
          console.log(i)
        }
      }(i)
    }
    

    又一个题目

    var fnArr = [];
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  function(){
        return i
      };
    }
    //var fn = fnArr[3]
    //fn()  调用时才有i,先执行for循环
    
    console.log( fnArr[3]() ) // 10,怎么输出1,2,3...,9
    
    var fnArr = []
    for (var i = 0; i < 10; i ++) {
      fnArr[i] =  (function(j){
        return function(){
          return j
        } 
      })(i)
    }
    console.log( fnArr[3]() ) // 3
    
    var fnArr = []
    for (var i = 0; i < 10; i ++) {
      (function(i){
        fnArr[i] =  function(){
          return i
        } 
      })(i)
    }
    console.log( fnArr[3]() ) // 3
    
    //使用ES6语法let,创建一个作用域
    var fnArr = []
    for (let i = 0; i < 10; i ++) {
      fnArr[i] =  function(){
        return i
      } 
    }
    console.log( fnArr[3]() ) // 3
    

    我们做了两个面试题目,发现在ES5中使用立即执行函数就可以打印出我们需要的东西

    • 立即执行函数创造了新的作用域
    • 造成上面的原因是闭包
    • 闭包作用暴露局部变量

    相关文章

      网友评论

          本文标题:js小知识点串讲

          本文链接:https://www.haomeiwen.com/subject/mgssextx.html