在咱們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
若是你以爲個人文章對您有幫助,給點鼓勵,謝謝html