js小知识点串讲

变量的生命周期

  • 看几个小例子
//问题一: 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中使用立即执行函数就可以打印出我们需要的东西

  • 立即执行函数创造了新的作用域
  • 造成上面的原因是闭包
  • 闭包作用暴露局部变量
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 34,922评论 18 399
  • 不曾在你巅峰时慕名而来,也未曾在你低谷时离你而去,我生活在你的时代,当然会做好准备,等着你的王者归来。
    蜂鸟1号阅读 330评论 0 0
  • 北方的秋雨总是要冰冷些的,蜷缩在搞搞的毛领里,踏着细雨前行。找到那家名做乐水名苑的地方。 很难想象繁闹商业区地带有...
    白鹿依依Batlu阅读 1,434评论 1 0
  • 夜晚 空荡的街道 一个人散步的生活 曾经 热闹的人海 两个人牵手的时光 如今 路过的风景 枯萎的花草,寂寞的白云 ...
    阿琴姑娘阅读 1,077评论 51 100

友情链接更多精彩内容