zoukankan      html  css  js  c++  java
  • js变量作用域,变量提升和函数传参

    参考:

    https://blog.csdn.net/alokka/article/details/88532347 (全局作用域,局部作用域,块作用域)

    https://blog.csdn.net/qq_39712029/article/details/80951958 (变量提升)

    全局作用域

    1,用 var 在全局(函数外)声明的所有变量,都具有全局作用域,即: 网页中所有脚本和函数均可使用。

    var carName = " Volvo";
    // 此处可调用 carName 变量
    function myFunction() {
        // 函数内可调用 carName 变量
    }

    2,没有声明的变量(没有使用var)会自动提升到全局作用域

    如果是在函数里面,需要执行函数才能生效,并且也只有在函数执行后面的作用域才能使用

    //情形1
    console.log(op1);//会报错
    op1='ddd';
    console.log(op1);
    
    //情形2 
    console.log(op2);//undefined
    var op2='ddd';//因为变量有提升
    console.log(op2);//ddd
    
     
    //情形3
    console.log(carName)//会报错
    function myFunction() {
        carName = "Volvo";
        // 此处可调用 carName 变量
    }
    //需要执行myFunction后才能使用

    局部作用域(即函数作用域别去追究)

    1,函数内部什么定义的变量,只在函数内使用;

    2,生命周期:在函数调用时临时生成,调用结束后就释放;

    块作用域

    JS中作用域有:全局作用域、函数作用域,没有块作用域的概念。

    支持块级作用域的编程语言:java,c++,c
    不支持块级作用域的编程语言:javascript,php,python

    for(var i = 0; i < 4; i++) {
            var d = 5;
        };
    console.log(i);    // 4   (循环结束i已经是4,所以此处i为4)
    console.log(d); // 5

    但是es6新增了块作用域,即使用let和const实现块作用域;

    for(let i = 0; i < 4; i++) {
      const d=i;
      console.log(d);//0,1,2,3,说明每次循环体内,都是一次新的作用域
    };
    console.log(i);  //会报错
    console.log(d); //会报错

    变量提升

    1,js代码自上而下执行之前,浏览器首先会把当前上下文中所有带“var / function”关键字进行提前的声明和定义,解析到它们对应作用域开始的位置,这种预先处理的机制叫做变量提升,变量提升的意义在于创建变量前使用这个变量不报错。

    2,变量提升也可以称之为预解析。可以理解为这是词法解析的一个环节,语法解析发生在代码执行前;

    3,JavaScript 仅提升声明,而不提升初始化;

    4,函数和变量相比,会被优先提升

    变量提升

    我们习惯将var a = 2;看做是一个声明,而实际上javascript引擎并不这么认为。它将var a和a = 2看做是两个单独的声明,第一个是编译阶段的任务,而第二个则是执行阶段的任务。

    例子1:

    console.log(v1);
    var v1 = 100;
    function foo() {
        console.log(v1);
        var v1 = 200;
        console.log(v1);
    }
    foo();
    console.log(v1);
    
    //结果
    //undefined //undefined //200 //100

    实例2:

    var name = "world";
    (function(){
      if(typeof name === "undefined") {
        var name = "Jack";
          console.log("Hello " + name);
      } else {
        console.log("Hello " + name);
      }
    }());
    
    //解析:相当于
    var name = "world";
    (function(){
      var name; // 变量提升,仅提升声明,不提升初始化
      if(typeof name === "undefined") {
        name = "Jack";
        console.log("Hello " + name);
      } else {
        console.log("Hello " + name);
      }
    }());

    函数提升

     javascript中不仅仅是变量声明有提升的现象,函数的声明也是一样;具名函数的声明有两种方式:

    //函数声明式,函数提升是整个代码块(相当于申明和初始化都提升了)提升到它所在的作用域的最开始执行
    function bar () {}
    //函数字面量式,这种情况和变量提升是一样的 var foo = function () {}

    实例1

    foo(); //1 ,因为函数提升比变量提升更优先
     
    var foo;
    function foo () {
        console.log(1);
    }
    
    foo = function () {
        console.log(2);
    }

    变量的值传递和引用传递

    // 基本类型
    var num1 = 5;
    var num2 = num1;
    num2 = 10;
    console.log(num1 + ' | ' + num2); // 5 | 10
    
    // 引用类型
    var obj1 = new Object();
    obj1.num = 5;
    var obj2 = obj1;
    obj2.num = 10;
    console.log(obj1.num + ' | ' + obj2.num); // 10 | 10

    一句话,引用类型复制的是指针的指向。

    函数传参

    一 ,参数

    1, 所有的参数传递,都是传递值的拷贝。(如果想知道为什么,去学习编译原理的函数调用的参数压栈和出栈对应内容)。

    2 ,C传指针进去,其实也是把这个指针值按拷贝传送进去。但是因为指针值指向一块外部内存空间(其实更多是堆空间,或外层栈变量空间),所以感觉可以在函数里改变外部变量。其实本质还是按拷贝传递,只是传递进去的是一个访问变量的渠道。
    因此,如果我们希望函数内能改变外部的指针值,往往传进去的是指针变量的指针。呵呵,很多初学C的程序员,对**非常难理解。

    二 ,返回值

    返回值是按拷贝传递,函数出栈后,会传出一个值,该值在调用函数的代码段的生命周期里一直有效。相当与调用点形成一个匿名的栈变量。
    变量a = function(); 而a并不等于函数里return的那个值。
    其实function()执行结果自身就是一个匿名变量。(其实编译器会检查语法,如上面a=function这样的语法,匿名变量不会生成,直接使用a变量拷贝返回值)
    例如: function()返回int值。 完全可以 int x = function() + 6;//注意:+运算时,函数已经执行完毕,所有函数出栈操作已经结束。
    很明显function()必须有一个变量或常量参与计算,而函数里return的值会随函数调用结束出栈而被删除,所以必须拷贝构造传递出来。

    上代码:

    var a = {
    num:'1'
    };
    var b = { num:'2' }; function change(obj){ //obj.num = '3';// obj = {
    num:'3'
    }; return obj.num; } var result = change(a); console.log(result + ' | ' + a.num); // 2 | 3
  • 相关阅读:
    Client-Side Template Injection with AngularJS
    502 BAD GATEWAY-k8s的cgroup限制了apache的可用内存
    alertmanager的web页面显示UTC时间的问题
    结构化数据
    天马行空 + 行业趋势
    elasticsearch备份脚本
    mongodb的安装部署-备份
    redis安装-备份-恢复 -- redislive -- web管理工具
    elasticsearch 的post put 方式的对比 setting mapping设置
    用elasticsearchdump备份恢复数据
  • 原文地址:https://www.cnblogs.com/tkzc2013/p/10640715.html
Copyright © 2011-2022 走看看