作用域和作用域链 scrope

作用域

什么是作用域?
        一个变量的可用范围

        避免函数内外(作用域)的变量之间互相干扰
作用域分为两种:

  1. 全局作用域:window对象
           保存着所有的全局变量
           随处可用
           可反复使用
           极易被污染
  2. 函数作用域:
           函数内的范围成为函数作用域
           出了函数{ }不能使用
           不能重复使用
//全局作用域
var  a = 10;
function fun (){
   //函数内的范围成为函数作用域 (局部变量)
   var a = 100;
   a++;
   console.log(a) //这里的a输出是101
}
fun()
console.log(a);  //这里的a输出是10

函数生命周期

一个函数从创建,到调用,最后到调用完所经历的阶段。

定义函数时

  1. 创建函数对象
  2. 创建函数变量名,保存函数对象的地址

调用函数时:

  1. 临时创建本次函数调用的函数作用域对象
  2. 在函数作用域对象中,创建本次函数所需的所有局部变量
         ①在函数内 var定义的变量
         ②形参定义的变量 (形参变量虽然没有 var ,但是也属于局部变量) 
  3. 在函数执行过程中 函数优先使用局部变量 没有的话去找全局变量

函数调用后(函数执行完):

  1. 释放函数作用域对象 
  2. 导致函数作用域对象中的局部变量也跟着被释放了
    (意味着 函数作用域的变量 也就是局部变量都不可重复使用

按值传递

什么是按值传递?

      在两个变量间赋值时,或者 将变量作为参数掺入函数时,其实只是将原变量的值复制一个副本          给对方变量。  (只要是赋值都存在按值传递!!!)

赋值的使用情况:
       ① 变量赋值   a=10
       ② 函数传参赋值  function  fun ( a, b){
                                      a=3;
                                      b=5;
                                   };
                                   add(3,5)

        ③对象的属性赋值(:冒号赋值) var lilei={
                                                             sname:"Li Lei"
                                                         }
        ④ 双向绑定(vue中) :titel="title"
注:
  修改副本,不会影响原来的值?

        如果传递的是原始类型的值,在函数中修改新变量,不会影响到原变量的值

        如果传递的是引用类型的值,因为复制的是地址值,造成了两个变量引用同一个对象,所以            任何一方修改都会受影响

两个变量间赋值时:(以下传递的是原始类型的值)

var h = 10;
var i = h; //按值传递 
//=右边的赋值其实是将原来变量中的值(var h = 10)再复制一个副本,给i变量 此时i 的值也为10 (内存中会有两个10) 但是是副本 所以不对原来的h造成影响 (也就是对原始类型的值来说 修改变量中的副本 不影响原来的变量)
i++;
console.log(h)  //h 的输出依然为10

两个变量间赋值时:(以下传递的是引用类型的值) 

var xiaoming = ["包子","包子","包子","包子"]  //定义一个数组 假设小明有四个包子
var  xiaohong = xiaoming //此时赋值 因为是引用类型的值,并不会把数组的值直接创建一个副本给 
                           xiaohong变量 而是把数组内存中引用的地址给xiaohong变量,
                           此时xiaohong得到的副本是地址值 而不是 实际数组 !!!
                           因为内存中两个地址指向的都是一个内容 ["包子","包子","包子","包子"]
                           那么xiaohong.pop()吃掉了一个包子 此时内容为 ["包子","包子","包子"]
                           就是3个包子,那么最后地址中引用的就会是三个包子
xiaohong.pop(); //假设小红此时吃掉了一个包子
console.log(xiaoming.length)  // 3

将变量作为参数传入函数时: 

var d = 10;
function fun (d){
           //副本10
   d++;
   console.log(d)  // 11
}
fun(d); //传参d相当于给形参变量赋值 也就是再fun(){ }里边 var d; 也就会形成按值传递
        //那么就将全局变量中的d=10,复制一个副本给 fun(){ }里边的d 也就是10,所以再函数内修改d,不 
          会影响到全局变量的d
console.log(d)   //10

 

以下情况表示 按值传递不只有一种情况 
    修改student2对象中的 原始类型的值时,原变量student不会改变
    修改student2对象中的 引用类型的值( student2.school{ } )时,原变量student中的       ( student2.school{ } )也会改变

扩展 作用域笔试题: 

var b = 10;
function fun2(){
   b=100;  //2.其次没有再函数体里边var定义变量 就没有局部变量,那么就会找到全局变量的b 进行赋值 所有的b都会对全局的b进行改变 此时b=100 就会更改全局中的b为100 
   b++;
   console.log(b); //101
}
fun2(); // 1.首先此时没有对函数进行传参
console.log(b); //101

作用域链

什么是作用域链?

    有多级作用域串联形成的链式结构
    每个函数在创建时,就有了自己的作用域链,
    普通函数作用域链里边包含2个内容:
      ①一个离自己近的,暂时为空 调用函数时 用来引用函数作用域对象 (局部)
      ②一个离自己远的 为window 始终保持着全局作用域对象  (全局)
     作用域 保存着一个函数可用的所有变量 控制着变量的使用顺序 先局部 局部没有 再全局!     

js中没有块级作用域

什么是块级作用域?

程序块:除函数以外的循环和分支的 {  } 里的 称为程序块
             如:for( ){ xxx }     if( ){ xxx } else{ xxx }
因为js中没有块级作用域 ,所以即使再循环内和分支内声明的变量,即便出了分支  { } 也照样使用

   声明提前:

在程序开始执行前,都是先在整段程序中 查找var声明的变量和 function声明的函数,将他们的定义提前到当前作用域的顶部集中创建赋值留在原地。

因为声明提前 function fun()声明的函数被提提前 会在函数执行前:
    function fun( ){ console.log(1) }
    function fun( ){ console.log(2) }
由于在  html js css 中都是 解释执行  那么后边的同名的内容会覆盖前边的function 所以只剩一个
    function  fun( ){ console.log(2) }
那么 fun() fun() 执行结果都是 2

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值