美文网首页
变量作用域问题,函数传参问题,null 问题

变量作用域问题,函数传参问题,null 问题

作者: 你隔壁的陌生人 | 来源:发表于2018-03-21 10:06 被阅读0次

    1、null的使用

    在网上找了这么一段话:

    NULL,可以近似理解为变量未赋值(定义了变量,但是未使用,变量不指向具体存储空间,因此,理论上不消耗存储空间),同时,它理论上不可以输出,因为变量本身没有内容。

    空“”,你可以近似理解为空串(定义了变量,并且赋值为空,这个空是具有含义的,需要消耗存储空间),可以输出来,展示表现为空。

    一个变量等于null表示这个变量还不存在,一个变量不等于null,即使内容为空,这个变量也是存在的。null用来判断这个变量对象是否存在,并不是内容是否为空

    var hello = document.getElementById("player").innerHTML;

    if (isNaN(num) || num < 6 || num > 18) {

    alert("请输入6-18的数字"); //验证数字

    } else if (hello === null) { //使用 null 判断是否有内容是错误的,alert函数不会被执行。因为空内容不等于hello是无的状态。

       alert("请设置玩家数量");

    } else {

    location.href = 'turnover.html';//跳转

    }

    所以当我判断一个标签内容是否为空时不能使用null,使用 null 判断是否有内容是错误的,alert函数不会被执行。因为空内容不等于hello是无的状态。好比一个创建了一个名字,但是没有没有代表任何东西,是无的状态,就是null,不占内存。空是创造了内存,但是没有内容。

    判断内容是否为空可以使用布尔值,空  ""  .

    var hello = document.getElementById("player").innerHTML;

    if (isNaN(num) || num < 6 || num > 18) {

    alert("请输入6-18的数字"); //验证数字

    } else if (hello == false) { //使用 布尔值 判断 是否有内容

       alert("请设置玩家数量");

    } else {

    location.href = 'turnover.html';//跳转

    }

    // var hello = document.getElementById("player").innerHTML;

    // if (isNaN(num) || num < 6 || num > 18) {

    //     alert("请输入6-18的数字");                                     //验证数字

    // } else if(hello === "" ){     // 使用空引号 “ ” 判断 是否有内容

    //     alert("请设置玩家数量");

    // }else {

    //     location.href = 'turnover.html';//跳转

    // }

    2、还是函数变量作用域的问题

    var mytime; //放在函数里不起作用?(变量初始化,将定时器清除了.

    // 每次执行函数都会从新定义这个变量,这个变量没有初始化,

               // clearInterval(mytime);就没有意义。放在函数外面,当执行一次函数后,

               // 这个变量就初始化为mytime = setInterval(start, 1000); 。从而保存了一个值。后面函数执行就可以调用)

    function myFunction() {

    clearInterval(mytime); //清除定时

       mytime = setInterval(start, 1000); //连续执行定时

       // setInterval('start()', 1000);

    // setInterval(function(){ start() }, 1000);

    }

    var mytime; 这个变量放在函数内部时mytime会出现错误,报错为“分配的价值从未被用过。”定时器无效。

    // 这个变量就初始化为mytime = setInterval(start, 1000); 。从而保存了一个值。后面函数执行就可以调用)

    function myFunction() {

    var mytime;

       clearInterval(mytime); //清除定时

       mytime = setInterval(start, 1000); //连续执行定时

       // setInterval('start()', 1000);

    // setInterval(function(){ start() }, 1000);

    }

    经过师兄帮忙讲解,总算是了解了:每次执行函数都会从新定义var mytime这个变量,而刚开始时var mytime这个变量没有初始化, clearInterval(mytime);就没有意义,定时器无效。当var mytime放在函数外面,执行一次函数后,这个变量就初始化为mytime = setInterval(start, 1000);  。从而保存了一个值。后面函数执行就可以继续调用了。

    3、函数参数的传递:

    高程讲函数参数是按值传递的。基本类型变量的传递很好理解。函数内基本类型变量发生改变,不会影响函数外部的变量的值。

    高程的例子:

    function addTen(num) { 

      num += 10;  

    return num; 

     var count = 20; 

    var result = addTen(count);

     alert(count); // 20, 没有变化

     alert(result); // 30

    这个基本类型的传递参数还是比较好理解的。将count 的值传递给函数的参数num,也就是将count 的值20复制给了函数参数num。从此count 与num两不相干,所以当num改变时count 不变。这与变量的复制一样。

    但是给函数传递对象时就比较难理解了。看例子

       function setname(obj){

    obj.name = "hello";

           obj = new Object();

           obj.name = "你好";

    //        return obj.name;

       }

    var person = new Object();

       setname(person);

       console.log(person.name); //hello

       console.log(setname(person)); //undefined

     当将对象person传递给函数的参数obj后,实际上是将person对象的指针复制给了obj,person与obj指向同一个对象(在堆内存)。所以当obj改变时,相应的person对象也会有反应,存入name : "hello"。

    为什么最后不是打印“你好”出来?

    当在函数内部从新定义一个新的对象,并将这个对象的指针复制给obj,此时obj的指针就从指向person 改成了指向这个新定义的对象obj.name = "你好";是给这个新的对象存值,不是person了。所以console.log(person.name);  还是hello(在开始时person传入函数,复制指针给obj,obj指向person,创建了name : "hello"。此时person就保存了hello)。

    console.log(setname(person)); //undefined   函数打印出undefined 是因为函数没有return出东西,函数在执行完毕后就被销毁了。但是当  return obj.name;  时,console.log(setname(person)); 就可以打印出 “你好”。

    第二个例子:

       var a = {value: 111};

       var b = {value: 222};

       function changeStuff(obj){

    obj.value = 333;

           obj = b;

           obj.value = 444;

           return obj.value;

       }

    console.log(changeStuff(a));              // 444

       console.log(a.value); // 333

       console.log(b.value); //444

     首先 a 对象传入函数,将a 对象保存在栈 中的指针复制给形参obj,这时候 obj.value = 333;  a 对象value值改变为 333;接下来 将 b 对象保存在栈中的指针复制给 obj ,这时候obj 从开始 保存 a 对象的指针 被替换为指向 b 对象的指针。当 obj.value = 444; 时,实际改变的是 b 对象的value值。所以最后打印出来  a 为333; b 为444 ;函数为 444。

    从知乎上看到一篇文章这样写:

    基本类型是传值调用

    引用类型传共享调用

    传值调用本质上传递的是变量的值的拷贝。

    传共享调用本质上是传递对象的指针的拷贝,其指针也是变量的值。所以传共享调用也可以说是传值调用。

    所以《JavaScript 高级程序设计》说 JavaScript 参数传递都是按值传参也是有道理的。

    链接:https://zhuanlan.zhihu.com/p/25314908

    4、关于变量在 栈 和堆内存的情况,

    1、基本类型变量 值保存在栈内存中,占有固定大小的空间,可以通过按值来直接访问。

    2、对象数组等引用类型保存在堆内存中,并在栈内存中创建一个指针,指向堆内存对象。这些引用类型的值大小不固定,通过保存在栈中的指针访问,也就是按引用访问。

    5、关于变量寿命,网上查找的资料:

    基本类型在当前执行环境结束时销毁,而引用类型不会随执行环境结束而销毁,只有当所有引用它

    的变量不存在时这个对象才被垃圾回收机制回收。

    1、堆内存释放或销毁:把所有知道该引用地址的变量赋值null,即没人知道该引用地址,浏览器就会在空闲的时候销毁它,也叫垃圾回收

    2、全局作用域的栈内存:页面关闭的时候,才会销毁

    3、私有作用域的栈内存(只有函数执行的时候才有私有作用域):

    a.一般情况:函数执行会形成一个新的私有作用域,当私有作用域的代码执行完之后,栈内存会自动销毁和释放

    b.特殊情况:1、函数执行返回一个引用类型的值,且在别的作用域被接收了,该栈内存不会被销毁

    2、私有作用域中,给DOM元素的事件绑定方法,该栈内存不会被销毁

    相关文章

      网友评论

          本文标题:变量作用域问题,函数传参问题,null 问题

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