在我们js中存储数据的空间可以分为两种,堆内存和栈内存
堆内存:我们定义的那些引用数据类型的数据都会在堆内存中开辟空间。
栈内存:我们运行的js代码还有我们定义的基本数据类型,都直接在栈内存中存储
基本类型 Undefined ,Null ,Boolean ,Number,String 该五种类型在内存中占用空间,即
值保存在栈内存中,可以提高查询变量速度,我们说他们是按值访问的
引用类型
引用类型,内存地址存在栈中,实际值存在堆内存。在堆内存中为这个值分配空间,因为这个值不确定大小,因此不能把它保存在栈内存中,因此把内存地址保存在栈内存中。
预解释 1,在JS运行之前,先会找所有带var和function关键字的,先把她们声明 2,找完了,再从上到下执行js代码 3,function在等号右边,这个function不会预解释
带function关键字的(就是定义函数),在整个脚本执行之前,就已经把函数名(其实就是变量名)在内存里安排好了,并且给这个函数名赋了值(就是函数体)
function关键字定义的,会把function内容(名字和函数体)都加在栈内存中。
//var a; //遇见var,先把a声明,分配地址。 即var=a;
alert(a);
var a=10;
alert(a);
---------------------------------------------------------------------------------------
        fn();//1
        function fn() {
            //alert(arguments.callee); //arguments.callee 函数自己 function fn() { alert(arguments.callee); //arguments.callee 函数自己
            alert(1);
        }
        fn();
带var和function的预解释是不一样的 1,var关键字是声明, 2,functions不仅声明了而且还定义了,它存储的是代码字符串没有任何意义
预解释是发生在作用域下的,刚开始进来的时候,我们预解释的是全局作用域(Global),在js中我们的globe就是window。
如果在当前作用域下的一个变量,没有预解释。就向他的上一级去找,直到找到window为止,如果window也没有定义,就被报错误。xxx is not defined
function:我们运行函数的时候,会生成一个新的私有作用域(我们可以理解为开辟一个新的栈内存),在这个内存中,我们也要执行我们的预解释机制
当我们的函数执行后,这个内存或者作用域就会被销毁。
function的运行周期,一个function从window下的预解释的时就声明并定义了,当function执行的时候会产生新的作用域,当function执行完成,
通常这个这个作用域会被销毁。
预解释只发生在var 和 function 上。
   -------------------------------------------------------------------------------------------------------------------------------------------
  
       fn(); //报错 找不到fn
        var fn1= function fn() { 
            //alert(arguments.callee); //arguments.callee 函数自己 function fn() { alert(arguments.callee); //arguments.callee 函数自己
            alert(1);
        }
         fn(); //报错 找不到fn
            //预解释只会对等号左边有效果,所以这里fn1会预解释,但右边不会被预解释 相当于 fn1=function(){    函数体}
-------------------------------------------------------------------
        var n = 9;
        var s = "str";
        function fn() {
            alert(n);
            alert(s);
            n = 7;
            s = "rts";
            var n = 6;
            alert(n);
        }
        fn();
        alert(n);
        alert(s);
undefind  ,str ,6,9 , rts
-------------------------------------------------------------------------------------------------------  
    <script>
        alert(a); // a is not defined
    </script>
    <script>
        var a = 1;
    </script>
    <script>
        alert(a);//1
    </script> 
预解释只对当前脚本块中起作用
-------------------------------------------------------------------------------------------------------
alert(a);
var a=12;
var a;
var a;
alert(12);
undefined  , 12
------------
function a(){}
var a;
alert(a);
弹出 function a(){} 因为function a也是预解释
预解释不会在同一变量上重复发生。即var a=12;已经预解释,后面的var a不会在执行。
--------------------------------------------------------------------------------------------------------
alert (f);
fn(); //没有预解释,所以报错
var f=funcion fn(){ alert("ok");}
undefind, fn is not defined
系统找不到fn,所以调用fn会报错。
JS只对等号左边带var 和 function 预解释 。等号右边是赋值,不会预解释。
-------------------------------------------------------------------------------------------------------
        var a = 12;
        function a() {alert(1);}
        alert(a);
        a(); //a is not a function
在项目中,切记不要让函数名和变量名相同
function a和 变量 a (没赋值),function a会覆盖变量a      
  var a ;
        function a() {alert(1);}
        alert(a); //function a() {alert(1);}
        a(); //弹出1
function a和 变量 a ( 赋值),变量a会覆盖function a
 var a = 12;
        function a() { alert(1); }
        alert(a); //弹出12
        a(); //a is not a function 
--------------------------------------------------------------------------------------------------------
alert(a);
if(1==2)
{
    var a=12;
预解释是不受if获其他判断条件影响的。即使条件不成立,条件里只要有var或function也会被预解释。
-----------------------------------------------------------------
if(!("a" in window)){ var a= "珠峰培训";} 
alert(a);
//undefined 因为a在预编译中声明了
----------------------------------------------------------------
我们的预解释也不会受到function的return影响
   function fn() { alert(1); };
        function fn2() {
            alert(fn);
            fn = 3;
            alert(fn);  
            return;
            function fn() { alert(2); }
        }
        fn2(); //function fn() { alert(2); }  -- 3
定义一个function,如果我们只是return,没有返回任何东西外面接收的也是undefined。
不加return,也是undefined
-----------------------------------------------------------------
 var f=function fn(){ alert(); }
//等号右边当成一个值,不会被预解释,所以系统找不到这个函数。 
alert(typeof f); //function
预解释,f是个变量
function fn(){}
预解释 fn是个function
-----------------------------------------------------------------
闭包:当我们的一个函数返回一个新的函数,我们在外面定义一个变量来接收,这样这个函数的内存就不能在执行完成之后自动销毁,也就是所谓的函数内存被占用了。(前提是我们返回的function里面有需要外面函数的东西)
在函数总可以(嵌套)定义令一个函数时,如果内部的函数引用外部函数的变量,就会产生闭包
     闭包其实就是函数在运行的时候产生的那个私有作用域。
     闭包的作用说的更直白一些就是为了让变量更安全,让一个环境中的变量与其它环境中的变量隔离开不产生冲突
    闭包是形成的私有作用域 ,让内部的变量不受外部函数影响
  最外层的function内,内存被占用,得不到释放。                                      
-------------------------------------------------------------------
        var n = 0;
        function a() {
            var n = 10;
            function b() {
                n++;
                alert(n);
  }
            b();    
            return b;
        }
        var c = a();
        c();
        alert(n);
11
12
0
相当于
         var n = 0;
        function a() {
            var n = 10;
            return function () {
                n++;
                alert(n);
            }
        }
        var c = a();
        c();
        c();
----------------------------------------------------------------------
        var n = 99;
        function ourer() {
            var n = 0;
            return function inner() {
             return n++; //return 直接返回的那个,其实是一个结果或者是值,是不需要预解释的。
            //this.n++;
            }          
        }
        var c = ourer();
//var c=funciton inner(){return n++;} 直接去上一级找,n=0  this.n=99
        var num1 = c(); //0
        var num2 = c(); //1
        alert(num1);
        alert(num2);
 
 -------------------------------------------------------------------
;()();
;(funtion(){         函数体   })();
如果我们想要在闭包中使用我们的全局变量
1,传参数
2,window
3,私有作用域下声明同名的变量
--------------------------------------------------------------
this只存在于function中
this表示谁,由当前调用这个方法的主体来决定
this关键字和在哪个作用域下执行也没关系,和调用的主体有关系
就看这个点前面是什么,什么都没有就是window。
       var point = {
            x: 10,
            y: 20,
            moveTo: function (x, y) {
                var moveX = function (x) { this.x = x; }
                var moveY = function (y) { this.y = y; }
                moveX(x); //主体是window
                moveY(y);
            }
        }
        point.moveTo(100, 200);
        alert(point.x);//10
        alert(point.y);//20
        alert(x);//100
        alert(y); //200
-----------------------------------------------------------------------------------------------------------------------
var number=2;
var obj={
     number:4;   
             fn1:(funciton(){        //在这样一个闭包内,this指向window
            this.number*=2;        //这个this 是window
            number=number*2;   //迷惑人
            var number=3;
                return function(){
                            this.number*=2;
                            number*=3;  //指向外面的那个number=3 
                            alert(number);
                    }
                     })()
 }
var fn1=obj.fn1;             
  //fn1=     function(){
  //                           this.number*=2;
  //                          number*=3;  //指向外面的那个number=3 
  //                          alert(number);
  //                  }
alert(number);//4
fn1();                //alert(9);              window.number=4,    
obj.fn1();         
                   //      function(){        
                   //         this.number*=2;
                   //         number*=3;  //指向外面的那个number=3 
                   //          alert(number);
                   //    }()          this.number=obj.number*2=8     alert(27)                window.number=8,    
alert(window.number);
alter(obj.number);
---------------------------------------------------------------------------------
具体的应用实例:
有如下html代码,要求:点击下面的li,会弹出对应的索引号。
<ul>
<li>列表一</li>
<li>列表二</li>
<li>列表三</li>
<li>列表四</li>
<li>列表五</li>
</ul>
很多人给出了如下错误的代码(点击li时弹出的是5):
<script>
var oLis=document.getElementsByTagName('li');
for(var i=0; i< oLis.length; i++){
  oLis [i].onclick=function() {
//注意:这里的这个匿名方法,在循环运行的时候这个匿名方法本身并不运行,当点击某个li的时候,这个方法才运行呢。
    alert(i);
//这里的这个i不是在这个匿名方法里定义的,而是上一级作用域里定义的。当这句代码运行的时候,循环早已经结束,并且i已经等于oLis.length了。
这里的问题出在这个方法里用到的是上一级作用域里定义的变量,如果要解决这个问题。
  };
}
ps:个人理解,这里面i是个全局变量,所以点击触发的时i已经不是绑定时的值了
    
//事件绑定相当于做计划,当点击的时候才相当于执行计划,请参考第一天教材的事件绑定部分的描述
</script>
正确的代码一:
<script>
var oLis=document.getElementsByTagName('li');
for(var i=0; i< oLis.length; i++){
;(function(i){//这里的这个i,已经不是外面的那个i变量了。
  oLis [i].onclick=function() {      alert(i);   };
})(i);
}
</script>
把上面的代码分解一下:
当第一次循环运行的时候,i的值为0,则实际运行的代码如下:
;(function(i){//这里的这个i,已经不是外面的那个i变量了。
  oLis [i].onclick=function() {      
     alert(i); 
  };
})(0);//因为i第一次是0,那么这里就相当于把0做为实参传给这个要运行的匿名函数,当这个匿名函数运行的时候,实际执行的就是这句代码了:
oLis [0].onclick=function() { 
   alert(0);
};//alert里已经是一个具体的数值了,第一次是0,依次是1、2、3、4。
 
正确代码二:
<script>
function  fn(i){                 
oLis [i].onclick=function() {  alert(i);   };    
 }
var oLis=document.getElementsByTagName('li');
for(var i=0; i< oLis.length; i++){      
  fn(i);      //相当于在fn()里形成私有作用域,相当于形成闭包
 }
</script>
var m=999;
function fn(){
var n=m=i=9;
}
alert(m); //999
这里面,m和i是全局变量
----------------------------------------------------------------------
  var a=1;
  if(!"a" in window)
  {
       alert(a);
      var a=2;
  }
undefined //没有弹出
 var a=1;
  if("a" in window)
  {
       alert(a);
      var a=2;
  }
弹出1

如果你觉得我的文章对您有帮助,给点鼓励,谢谢

我的JavaScript笔记--数据类型,预编译,闭包的更多相关文章

  1. JavaScript作用域原理——预编译

    JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...

  2. javaScript语言的预编译与运行

    JS代码执行的过程: 1.预编译 ---- 事先对js代码做一个预处理 2.代码运行---开始执行JS代码. JS编程: 1.加载DOM的最好在/BODY之前 2.与DOM渲染无关的放在Head里面 ...

  3. JavaScript作用域及预编译

    几乎所有的编程语言都可以存储,访问,修改变量,那在JavaScript中这些变量放在那里?程序如何找到他们? js被归类于解释执行语言,但事实上他也是一门编译语言,因为他也要编译,但于传统的编译语言不 ...

  4. javascript中的预编译问题

    Js作为脚本语言,可以不需要编译直接运行,但遇到类似变量或者函数同名,预编译方面的知识可以帮助我们更好解决问题. 示例: 这是一段js中普通的函数调用代码 <script>1.    // ...

  5. JavaScript笔记:数据类型

    javascript中有5种基本数据类型:Undefined,Null,Boolean,Number和String,还有一种复杂的数据类型--Object.javascript不支持任何创建自定义类型 ...

  6. 一步一步的理解javascript的预编译

    首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...

  7. JavaScript作用域原理(二)——预编译

    JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...

  8. js中的预编译

    预编译 js执行顺序: 词法/语法分析 预编译 解释执行 js中存在预编译 function demo() { console.log('I am demo'); } demo(); //I am d ...

  9. JS笔记--------预编译,闭包和作用域

    (一)JS预编译四部曲: 1,创建AO对象. 2,找形参和变量声明,将变量和新参名作为AO属性名,值为undefined. 3,将实参值和形参值统一. 4,在函数体里找函数声明,值赋给函数体. (二) ...

随机推荐

  1. Eclipse Debug 使用

      Eclipse的debug模式:代码调试 * Eclipse或MyEclipse就是java的开发工具 * Eclipse开源的.免费的Java开发工具 * MyEclipse基于Eclipse开 ...

  2. 一个表中的字段值用作另一个表的In查询条件

    Question表与Paper表 Paper表中字段QuestionIds存储的是Question表中字段Id的拼接后的值 如: 'f855eba1-b308-4bd7-a250-c071a0e1bd ...

  3. Docker运行报Cannot connect to the Docker daemon错误

    核心问题所在:权限不足 操作docker命令提示:Cannot connect to the Docker daemon 请切换管理员权限,root权限,root安装的一般的用户访问会存在此问题.

  4. sklearn 随机森林方法

    Notes The default values for the parameters controlling the size of the trees (e.g. max_depth, min_s ...

  5. 删除Git记录里的大文件

    删除Git记录里的大文件 仓库自身的增长 大多数版本控制系统存储的是一组初始文件,以及每个文件随着时间的演进而逐步积累起来的差异:而 Git 则会把文件的每一个差异化版本都记录在案.这意味着,即使你只 ...

  6. APK反编译之一:基础知识

    作者:lpohvbe | http://blog.csdn.net/lpohvbe/article/details/7981386 这部分涉及的内容比较多,我会尽量从最基础开始说起,但需要读者一定的a ...

  7. Android Service演义

    摘要: 本文基于Android 5.1代码,介绍了Android Service的运作机理.按理说,网上此类文章已经很多了,本不需我再赘述.但每个人理解技术的方式多少会有所不同,我多写一篇自己理解的s ...

  8. 关于UNIX/Linux下安装《UNIX环境高级编程》源代码的问题

    <UNIX环境高级编程(第三版)>是一本广为人知的unix系统编程书籍. 但是,书中的代码示例,要想正确的编译运行,要先做好准备工作: 1.下载源代码 传送门:http://apueboo ...

  9. [JNA系列]Java调用Delphi编写的Dll之Delphi与JAVA基本数据类型对比

    Delphi与JAVA基本数据类型对比 类型 Delphi关键字 JAVA关键字 字节 备注 范围 整型 Shortint byte 1 有符号8位 -128..127 Byte 1 无符号8位 0 ...

  10. PHP学习笔记(14)班级和学生管理---学生

    两个文件夹,一个班级cls,一个学生stu. 两个表,一个班级cls,一个学生stu. 每个文件夹里有7个php文件:主界面stu.php-------增add.php,insert.php----- ...