在我们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作用域原理——预编译
JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...
- javaScript语言的预编译与运行
JS代码执行的过程: 1.预编译 ---- 事先对js代码做一个预处理 2.代码运行---开始执行JS代码. JS编程: 1.加载DOM的最好在/BODY之前 2.与DOM渲染无关的放在Head里面 ...
- JavaScript作用域及预编译
几乎所有的编程语言都可以存储,访问,修改变量,那在JavaScript中这些变量放在那里?程序如何找到他们? js被归类于解释执行语言,但事实上他也是一门编译语言,因为他也要编译,但于传统的编译语言不 ...
- javascript中的预编译问题
Js作为脚本语言,可以不需要编译直接运行,但遇到类似变量或者函数同名,预编译方面的知识可以帮助我们更好解决问题. 示例: 这是一段js中普通的函数调用代码 <script>1. // ...
- JavaScript笔记:数据类型
javascript中有5种基本数据类型:Undefined,Null,Boolean,Number和String,还有一种复杂的数据类型--Object.javascript不支持任何创建自定义类型 ...
- 一步一步的理解javascript的预编译
首先,我们要知道javascript是单线程.解释性语言.所谓解释性语言,就是翻译一句执行一句.而不是通篇编译成一个文件再去执行. 其实这么说还没有这么直观,读一句执行一句那是到最后的事了.到JS执行 ...
- JavaScript作用域原理(二)——预编译
JavaScript是一种脚本语言, 它的执行过程, 是一种翻译执行的过程.并且JavaScript是有预编译过程的,在执行每一段脚本代码之前, 都会首先处理var关键字和function定义式(函数 ...
- js中的预编译
预编译 js执行顺序: 词法/语法分析 预编译 解释执行 js中存在预编译 function demo() { console.log('I am demo'); } demo(); //I am d ...
- JS笔记--------预编译,闭包和作用域
(一)JS预编译四部曲: 1,创建AO对象. 2,找形参和变量声明,将变量和新参名作为AO属性名,值为undefined. 3,将实参值和形参值统一. 4,在函数体里找函数声明,值赋给函数体. (二) ...
随机推荐
- iOS AVPlayer视频播放器
代码地址如下:http://www.demodashi.com/demo/11168.html 一.运行效果 二.实现过程 ①.创建播放器avPlayer //创建播放器 url = [url str ...
- 用Fiddler 发送post请求
在调试web api的时候,若是get 请求,可以直接在浏览器里查看结果,如果是put,或者post请求在浏览器地址栏里就没有办法了. 下面介绍一下,如何利用fiddler模拟post请求. 也可以用 ...
- 如果你需要从不同的服务器(不同域名)上获取数据就需要使用跨域 HTTP 请求
Response.AppendHeader("Access-Control-Allow-Origin", "*")Response.AppendHeader(& ...
- .Net MVC ViewBag
ViewBag用来做视图的值绑定,我不清楚是不是这么称呼.之前看过安卓的值绑定做法,mvc直接动态类型,瞬间逼格满满 Controller: public class HomeController : ...
- atitit.破解 拦截 绕过 网站 手机 短信 验证码 之自动获取手机短信方式 attilax 总结
atitit.破解 拦截 绕过 网站 手机 短信 验证码 之自动获取手机短信方式 attilax 总结 1. 自动获取手机短信方式的原理 1 2. 调用api 1 3. ----核心代码 2 4. ...
- 解决eclipse偶尔无视breakpoint的行为
一般是如果你使用了T[]这样的参数列表,也就是generic array作为参数,你就算给函数打了断点,有时也会被eclipse无视 比如如下代码,你在调试main的时候,eclipse就会把doPa ...
- Struts2的简单使用
一.准备工作及实例 1.解压struts-2.1.6-all.zip apps目录:struts2自带的例子程序 docs目录:官方文档. lib 目录:存放所有jar文件. Src 目录:源文件存放 ...
- C#高级学习群欢迎你(群号 128874886)
C#高级学习群,有着C# ,Asp.net ,Wpf等技术经验相当丰富的工程师,秉承着刘群主开源共享的精神,为新手和高手们提供了良好的学习交流平台,自创群以来,为群员解决了不少的技术难题,大大提高了学 ...
- 编写可维护的JavaScript----笔记(一)
1.缩进层级 建议使用4个空格为一个缩进层级,避免使用制表符进行缩进,可以通过配置文本编辑器来改变 缩进层级表示的内容. 2.语句末尾 有赖于分析器的自动分号插入机制(ASI),JavaScript可 ...
- 禁用LinkButton的方法
1.服务器端,使用Enabled属性即可 <asp:LinkButton ID="lbtn" runat="server" Enabled="f ...