javascript 函數及作用域總結介紹_javascript技巧
在js中使用函數注意三點:
1、函數被呼叫時,它是運行在他被聲明時的語法環境中的;
2、函數本身無法運行,它總是被對象調用的,函數運行時,函數體內的this指針指向調用該函數的對象,如果調用函數時沒有明確指定該對象, this 默認指向window ( strict模式除外,本文不涉及strict 模式);
3、函數是一種帶有可執行程式碼的物件類型資料。
一、宣告函數
1、使用function 關鍵字
碼
function myfun(a,b){ //宣告名為myfun的函式
return a b;
2、 宣告匿名函數
function(a,b){ return a b;}匿名函數本身是無法保存的,由於在js中函數是一種物件型數據,因此可以把匿名函數賦給變數來保存。
var myfun = function(a,b){ return a b;}
Function 是js內建的函數,他是所有函數物件的建構器。 (其他資料物件也有自己的內建建構函數,像是Number,Object等,這些建構子自己的建構子就是Function,因為他們都是函數)。
var myfun = new Function('a,b','return a b;'); 其中最後一個參數是函數體,前面的參數都是函數的形式參數名,個數不定,因為需要用字串傳參來構造,函數較長時這種寫法很不方便,一般很少用,也許你會用它來構造特定的返回值從而取代eval函數。
function a(){ alert('a'); }
alert(window.a); //存取window物件的屬性也可以省去window不寫
var a=1;
with({}){
; //在firefox 下a 是未宣告
function a(){ console.log("function a is called");}
alert(func1);//彈出func1(){alert(2);}
func1(){
alert(1);
}
alert(func1); //彈出func1(){alert(2);}
func1(){ //這是最後一次宣告的func1,以此函數為準
alert(2);
}
alert(func1); //彈出func1(){alert(2);}
var func1 = function(){ //注意 ,這裡是變數賦值,不是函數宣告
alert(3);
}
程式碼如下:
if(function fun(){}){
alert(fun); // error,不會成功宣告名稱為fun 的函數,但在IE8 及以下的瀏覽器中會成功宣告一個函數fun
}
(function fun(){ });
alert(fun); //error但是即使在 IE8 一下, 表達式中的具名函數也不能覆蓋該作用於下同名的變數:
var fun = 1; //該變數不能被函數表達式中的函數名稱覆蓋
var f = function fun(){};
alert(f); //function fun(){ };
alert(fun); //1
注意區別:
if(fun = function (){}){
alert(fun); // ok,這裡宣告了一個變量,該變數保存了一個匿名函數
}
js函數是引用型的物件
var a = function(){};
var b=a;
b.x=2;
alert(a.x); //2
二、函數的參數
js函數不會檢查函數呼叫時傳入的參數個數與定義他時的形式參數個數是否一致,一般地,js函數呼叫時可以接收的參數個數為25個,當然不同的瀏覽器可能有差異,ECMAScript標準對這一點並沒有規範。
如果你不確定函數呼叫時傳入了多少個參數,可以使用函數的arguments物件。
arguments 有點像數組,arguments.length 為傳入的參數個數,arguments[0] 是第一個參數,arguments[1]是第二個參數,類推...
函數物件的length屬性:這個屬性很少用到,甚至很少人知道,函數的length屬性就是該函數定義時的形式參數個數。
function myfun(a,bb){
alert(arguments.length); //彈出呼叫時實際傳入的參數個數
alert(arguments[0]); //對應參數a
return a b;
}
alert(myfun.length); //形參數,2
arguments物件還有其他屬性,例如常用的arguments.callee ,指向該函數本身。
要注意:如果函數內部宣告了與形參同名的子函數(同域內,變數未賦值時同名函數生效),arguments 的對應值也會被修改,但是,在作用域內使用var 宣告了同名的變數則不會導致arguments 的參數值被函數取代(但firefox 依然替換)。
function aa(a , b,cc){ // js 群的一道題
function a(){}
console.log(a); //function a
console.log(aa); console.log(arguments[0]);
var a = "ee"; /註銷此句,考擦arguments[0] 將變成a 函數
var aa = "444";
arguments = 6;
console.log(a); console.log(arguments);
}
aa(1,2,3);
js函數使用 return 語句傳回值。 一切資料型別都可以當作函數的傳回值(包含函數),js函數也可以沒有傳回值。
四、函數呼叫
函數本身是不會運作的,當它運行時,總是存在一個呼叫它的物件。
預設情況下,在任何語法環境中,如果沒有明確指定函數的呼叫對象,就是指透過window對象來呼叫該函數,此時,函數體內的this指針指向window對象。alert(this);
return a b;
}
myfun(1,2); // 呼叫函數並傳入2個參數,這2個參數分別對應形式參數a,b呼叫函數時,如果傳入的參數個數超過形式參數,就只有用arguments加下標來接收了。
由於沒有明確指定呼叫函數的對象,alert(this)將彈出 window對象。這種呼叫方法是最常見的。
用於明確指定函數的呼叫物件方法有三:
1、如果一個函數被賦為一個物件的屬性值,這個函數只能透過該物件來存取(但並非是說該函數只能被該物件呼叫),透過該物件呼叫這個函數的方式類似以物件導向程式語言中的方法呼叫(實際上在js中也習慣使用方法這種稱呼)。
var obj={}; //定義一個物件
obj.fun=function(a,b){
alert(this); //彈出this指標
return a b;
} //物件屬性值為函數
alert(obj.fun);// 存取fun函數。 只能透過該物件來存取這個函數
obj.fun(1,2); //透過obj物件來呼叫fun函數,將彈出obj物件。這種方式也稱為呼叫obj物件的fun方法。
2、 任意指定函數的呼叫物件:在某個語法環境中,如果可以同時存取函數fun和物件obj,只要你願意,可以指定透過obj物件來呼叫fun函數。指定方法 有2種:call方法和apply方法。 (因為window物件是瀏覽器環境下的頂級對象,在任何語法環境中都能存取到window對象,因此,任何函數都可以透過window物件來呼叫)
function fun(a,b){
alert(this);
return a b;
}
var obj={};
fun.call(obj,1,2); //透過obj物件來呼叫fun函數,並傳入2個參數,彈出的指標為obj物件。
var obj2={};
obj2.fun2 = function(a,b){ //obj2物件的屬性fun2是一個函數
alert(this);
return a b;
};
obj2.fun2.call(obj,1,2); //透過obj物件來呼叫obj2物件的fun2屬性值所保存的函數,彈出的this指標是obj物件
//比較隱藏的方法呼叫:陣列呼叫一個函數[9,function(){ alert(this[0]); }][1]();
//使用window物件呼叫函數以下幾種方法是等價的
fun(1,2);
window.fun(1,2); //如果fun函數是全域函數
fun.call(window,1,2);
fun.call(this,1,2); //如果該句代碼在全域環境下(或被window物件呼叫的函數體內),因為該語法環境下的this就是指向window物件。
func.call(); //如果函數不需要傳參
func.call(null,1,2);
func.call(undefined,1,2);var name = "window ";
function kkk(){
console.log(this.name); // not ie
}
kkk(); //window
kkk.call(kkk); //kkk 函數被自己調用了
另一種比較容易疏忽的錯誤是,在A 物件的方法中,執行了使用了B 物件的方法調用,試圖在B 物件的方法裡使用this 來存取A 對象,這在各種回呼函數中比較常見,最常見的情形就是ajax 回呼函數中使用this 。
var obj = {
var obj = {
🎜> getData:function(){
$.post(url,{param:token},function(dataBack){ //jQu) dataBack; //試圖將伺服器傳回的資料賦給obj.data ,但這裡的this 已經指向jQuery 的ajax 物件了
},'json');
}}
}
}
}
}
//正確做法
var obj = {
data:null,
getData:function(){
. post(url,{param:"token"},function(dataBack){
host.data = dataBack;
3、apply方法呼叫:
apply方法與call方法唯一不同的地方是函數傳參方式不同。
obj2.fun2.call(obj,1,2); 改為 apply方式就是obj2.fun2.apply(obj,[1,2]);
apply使用類別數組方式傳參,除數組外,還可以使用arguments、HTMLCollection來傳參,但arguments並非數組,如:
var obj={};
function fun_1(x,y){
function fun_2(a,b){
return a b;
}
fun_2.apply(obj,arguments); //用fun_1的arguments物件來傳參,實際上是接收了x,y
}apply 傳參在IE8 及IE8一下的瀏覽器中喲2個問題
在call 和apply 調用中,如果傳入標量數據(true/false ,string,number),函數運行時將把他們傳入的基本數據包裝成對象,然後把this指向包裝後的對象,試試下面的程式碼。
function a(){
alert(typeof this);
alert(this.constructor);
alert(this);
}
a.call(false);
a.call(100);
a.call('hello');
甚至可以用這個特點來傳參數,但不建議這種用法:
function a(){ alert(1 this); } //物件在運算中自動進行型別轉換
a.call(100); //101
4、函數作為物件建構器
當函數使用new 運算作為對象建構器運行時,this 指向新構造出對象,如果該構造函數的返回值不是null 以外的對象,構造函數運行完畢將返回this 指向的對象,否則返回原定義的對象。
function Fun(){ function Fun(){
this.a = 1;
this.b = 3;
console.log(this); //{a:1,b:2}
// return {a:999}; //加上此舉 ,將回傳 {a:999}
}
var obj = new Fun(); //obj = {a:1,b:2} ,如果沒有參數,也可以寫成var obj = new Fun; 五、函數作用域
js的變數作用域是函數級的,在js裡沒有類似c語言的區塊級作用域。
js程式設計環境的頂級作用域是window物件下的範圍,稱為全域作用域,全域作用域中的變數稱為全域變數。
js函數內的變數無法在函數外面訪問,但在函數內可以存取函數外的變量,函數內的變數稱為局部變數。
js函數可以嵌套,多個函數的層層嵌套構成了多個作用域的層層嵌套,這稱為js的作用域鏈。
js作用域鏈的變數存取規則是:如果目前作用域內存在要存取的變量,則使用目前作用域的變量,否則到上一層作用域內尋找,直到全域作用域,如果找不到,則該變數為未宣告。
注意,變數的宣告在程式碼解析期完成,如果目前作用域的變數的宣告和賦值語句寫在變數存取語句後面,js函數會認為目前作用域已經存在要存取的變數不再向上級作用域查找,但是,由於變數的賦值發生的程式碼運行期,訪問的到變數將是undefined.
程式碼如下:var=1000 >
function out(){
var a=1;
var b=2;
function fun(){
alert(a); //undefined
var a=10;
alert(a); //10
alert(b); //2
alert(c); //1000
}
fun();
}
六、匿名函數的呼叫
匿名函數的使用在js很重要,由於js中一切資料都是對象,包括函數,因此經常使用函數作為另一個函數的參數或返回值。
如果匿名函數沒有被保存,則運行後即被從記憶體中釋放。
匿名函數的呼叫方式一般是直接把匿名函數放在括號內替代函數名。如:
(function(a,b){ return a b;})(1,2); //宣告並執行匿名函數,執行階段傳入兩個參數:1和2
//或
(function(a,b){ return a b;}(1,2));
//下面這種寫法是錯的:
function(a,b){ return a b;}(1,2);
由於js中語句結束的分號可以省略,js引擎會認為function(a,b){ return a b;}是一句語句結束,因此匿名函數只聲明了沒有被調用,如果語句沒有傳參( 1,2)寫成(),也會導致錯誤,js中空括號是語法錯誤。
下面這種寫法是正確的。
var ab = function(a,b){ return a b;}(1,2); // ab=3
js 解析語法時,如果表達式出現在賦值運算或運算子運算中,是"貪婪匹配"的(盡量求值)
function(t){ return 1 t;}(); //error
var f = function(t){ return t 1;}(); // ok
~ function(t){return t 1;}(); //ok
function(t){return t 1;}(); //ok
如果你只是想把一個匿名函數賦給一個變量,記得在賦值語句後面加上分號,否則,如果後面跟了小括號就變成了函數調用了,尤其是小括號與函數結尾之間分隔了多行時,這種錯誤往往很難發現。
實際開發中,匿名函數可能以運算值的方式傳回,這種情況可能不容易看出,例如
var a =1;
var obj = {a:2,f:function(){ return this.a;}};
(1,obj.f)(); //1 逗號表達式反悔了一個匿名函數,當這個匿名函數被呼叫時,函數體內的 thsi 指向 window
聲音 明並立即運行匿名函數稱為」自執行函數“,自執行函數經常用於封裝一段js程式碼。由於函數作用域的特點,自執行函數內的變數無法被外部訪問,放在函數內 的程式碼不會對外面的程式碼產生影響,可以避免造成變數污染。 js開發很容易造成變數污染,在開發中經常引入其他編碼人員開發的程式碼,如果不同的編碼人員定義了同名稱不同含義的全域變數或函數,便造成了變數污染,同一作用域內出現同名的變量或函數,後來的將覆蓋前面的。
(function(){
//自己的程式碼.....
})();匿名函數還可以讓記憶體及時釋放:因為變數被宣告在匿名函數內,如果這些變數沒有在匿名函數之外被引用,那麼這個函數運行完畢,裡面的變數所佔據的記憶體就會立即釋放。
函數的name:在firefox等瀏覽器,函數有一個name屬性,就是該函數的函數名,但是這個屬性在IE中不存在,另外,匿名函數的name為空值。
var a=function(){}
alert(a.name); //undefined,a是儲存了一個匿名函數的變數
function b(){}
alert(b .name); //b ,but undefined for IE
七、函數被呼叫時,運行在他被定義時的環境中
無論函數在哪裡被調用,被誰調用,都無法改變其被聲明時的語法環境,這決定了函數的運行環境
var x=99;
var inerFun=null;
function fun1(){
alert(x);
}
function holder(){
var x = 100;
var fun2 = fun1;
inerFun = function(){ alert(x);}
fun1(); //99
fun2();//99
inerFun(); //100
}
holder();
fun1(); //99
inerFun(); //100
//另一個例子:
var x = 100;
var y=77;
var a1={
x:99,
xx:function(){
//var y=88; / /如果註解這個變量,y將是全域變數的77
alert(y); //沒有使用this指針,呼叫函數的物件無法影響y的值,函數執行階段將從這裡按作用域鏈逐級搜尋取值
alert(this.x); //使用了this 指針,呼叫函數的
}
}
a1.xx();
a1.xx.call(window);
var jj = a1.xx;
jj(); //效果跟a1.xx.call(window); 一樣//試試看下面程式碼
var x=99;
function xb(){
this.x=100;
this.a = (function(){return this.x}).call(this); / /new 的時候執行了,匿名函數被實例化的物件呼叫
this.b = (function(){return this.x})(); //new 的時候執行了,匿名函數被window調用
this.method = function(){return this.x;}
}
var xbObj = new xb();
console.log(xbObj.x);
console.log(xbObj.a);
console.log(xbObj.b);
console.log(xbObj.method());
注意區分呼叫函數的物件、函數宣告時的語法環境、函數呼叫語句的語法環境這幾個概念
1、呼叫函數的物件(或說函數的呼叫方式)決定了函數運行時函數體內的this指標指向誰
2、函數宣告時的語法環境決定了函數執行階段的存取權限
3、函數呼叫語句的語法環境決定了函數是否真的能夠被呼叫及何時被呼叫(只有函數在某個語法環境是可見的,這個函數才能被呼叫)
函數在運行時,產生一個 arguments 物件可以存取傳入函數內的參數,arguments 有一個屬性可以指向函數本身:arguments.callee.
函數運行時,函數的caller 屬性可以指向本函數調用語句所在函數,例如,a函數在b函數體內被調用,則當a函數運行時,a.caller就指向了b函數,如果a 函數在全域環境中被呼叫則a.caller=null
arguments 和a.caller 的值與函數的每一次呼叫直接關聯,他們都是在函數運行時產生的,只能在函數體內存取。
IE8及IE8以下瀏覽器中,a 函數的內的arguments.caller( IE9之後這個屬性被移除) 指向a.caller 執行時的arguments (arguments.caller.callee === a.caller),
七、字串即時解析中的函數呼叫:eval()、new Function()、setTimeout()、setInterval()
eval() 與window.eval()
function a(){
console.log('out of b');
}
function b(){
function a(){ console.log("in b"); }
var f = function(){ a(); };
eval('a()'); // in b
window.eval('a()'); //out of b ,ie 678 in b, ie 9 out of b
(new Function('a();'))(); //out of b
setTimeout('a()',1000); /; / out of b
setTimeout(f,2000);// in b
}
b();
eval() 中的程式碼執行於eval() 語句所處的作用域內:
var Objinit = function(){
var param = 123;
return {
eval(codes);
},
setCallback:function(f){
fireCallback:function(){
this.callback && this.callback。 > },
getParam:function(){
}
};
var obj = Objinit ();
var param = 'outerParam';
console.log(param,obj.getParam()); //outerParam 123
obj.execute('param = 456');
console.log(param,obj.getParam()); //outerParam 456obj.setCallback(function(){ eval("param = 8888")});
obj.fireCallback();
console.log(param,obj.getParam()) ; //8888 456
obj.setCallback(function(){ eval("eval(param = 9999)")});
obj.fireCallback();
console.log(param,obj.getParam ()); //9999 456eval()
字串中解析出的程式碼運在 eval 所在的作用域,window.eval()封裝運行在頂級作用域(低版本 chrome 及以下 IE9)則同eval())。
IE中,window.execScript(); 相當於window.eval()
new Function()、setTimeout()、setInterval() 的第一個字串參數所解析得到的程式碼,都是在頂層作用域執行。
八、函數閉包
要理解函數閉包,先了解js的垃圾自動復原機制。
number、string、boolean、undefined、null 在侵犯和賦值操作中是複製傳值,而物件類型的資料按引用傳值,js 的同一個物件類型資料可能被多次引用,如果某個物件不再被引用,或者兩個物件之間相互引用之外不被第三方所引用,瀏覽器會自動釋放其佔用的記憶體空間。 函數被引用:函數被賦為其他物件的屬性值,或是函數內部定義的資料在該函數外部被使用,閉包的基於後面的一種情況。 🎜>複製程式碼
程式碼如下:
var f;函數 fun(){
var a =1;
f(); // 閉包中 a =3 ,模擬靜態變數 在 fun 內宣告的匿名函數賦給 fun 外的變數 f,該匿名函數內使用了在 fun 內宣告的變數 a,現在f可以存取變數a,為了維持這種存取權限(f執行時需要存取a,但執行時未定),fun()執行完畢後產生的變數a不能被釋放(除非f中的函數被釋放),於是產生了一個封閉包(標誌a被封閉了,供f使用)。
產生閉包的關鍵是,一個在函數A內的聲明的函數B被傳出A之外,並且B函數內使用了在函數A內產生的數據(或按值傳參),
函數B傳出函數外部的方式有多種,如:
複製程式碼程式碼如下:
函數fun(){ var a =1;
return {a:123,b:456, c: function(){ return a;} };
}
複製程式碼 複製程式碼
var a =1;
警報(f1()); //2
警報(f1()); //3
警報(f2()); //2
警報(f2()); //3
這兩份閉包中的變數 a 是不同的數據,每產生一份閉包, fun() 執行了一次, 變數宣告語句也執行了一次。
js oop 程式設計中閉包可以用來模擬私有成員、建構單體類別
function MakeItem(name,val){
var myName,myVal; //私有屬性
//私人方法
function setName(name){
myname=name;
}
//私人 方法
function setVal(val){
myVal=val;
}
//執行new建構物件時呼叫內部私有方法
setName(name);
setVal(val);
//公共方法
this.getName=function(){
return myName;
}
this.getVal=function(){
return myVal;
}
}
var obj = new MakeItem("name",100);
obj.myname; //undefined 無法在外面存取私有屬性
obj.getName(); //ok
以下是單體類別建構方法
var Singleton = (function(){
var instance = null; //在闭包中保存单体类的实例
var args = null;
var f = function(){
if(!instance){
if(this===window){
args = Array.prototype.slice.call(arguments,0);
instance = new arguments.callee();
}else{
this.init.apply(this,args||arguments);
instance = this;
}
}
return instance;
};
f.prototype = {
init:function(a,b,c){
this.a = a;
this.b = b;
this.c = c;
this.method1 = function(){ console.log("method 1"); };
this.method1 = function(){ console.log("method 1"); };
console.log("init instance");
}
};
f.prototype.constructor = f.prototype.init;
return f;
})();
//单体的使用
var obj1 = Singleton(1,2,3);
var obj2 = new Singleton();
var obj3 = new Singleton();
console.log(obj1===obj2,obj2===obj3); //true
console.log(obj1);
//一个单体类声明函数
var SingletonDefine= function(fun){
return (function(){
var instance = null;
var args = null;
var f = function(){
if(!instance){
if(this===window){
args = Array.prototype.slice.call(arguments,0);
instance = new arguments.callee();
}else{
fun.apply(this,args||arguments);
instance = this;
}
}
return instance;
};
f.prototype = fun.prototype;
f.prototype.constructor = fun;
return f;
})();
};
var fun = function(a,b,c){
this.a = a;
this.b = b;
this.c = c;
this.method1 = function(){ console.log("メソッド 1") };
console.log("init インスタンス");
};
fun.prototype.method2 = function(){ console.log('メソッド 2') };
//単一クラス宣言関数の使用法
var Singleton = SingletonDefine(fun);
var obj1 = Singleton(8,9,10);
var obj2 = new Singleton();
var obj3 = new Singleton(3,2,1);
console.log(obj1===obj2,obj2===obj3);
console.log(obj1);
//console.log(obj1.toSource()); //firefox
obj1.method1();
obj1.method2();
IE6 でのメモリ リークとクローズ
IE 6 では、非ネイティブ JS オブジェクト (DOM など) への循環参照によりメモリ リークが発生します。クロージャを使用する場合は、非ネイティブ オブジェクト参照を使用するときに注意してください。
関数 fun(){
var node = document.getElementById('a');
node.onclick = function(){alert(node.value) };
node = null //メモリリークを防ぐために循環参照を解除します
ノードは、fun の外部に存在する DOM オブジェクトを保存します (常に存在し、削除されてもドキュメント ツリーから削除されるだけです) fun が実行された後、クロージャが生成され、これも DOM 間の循環参照を構成します。オブジェクトとコールバック関数 (ノード-関数-ノード) を使用すると、IE 6 でメモリ リークが発生します。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

熱門話題

typedef struct 在 C 語言中用於建立結構體類型別名,簡化結構體使用。它透過指定結構體別名將一個新的資料類型作為現有結構體的別名。優點包括增強可讀性、程式碼重複使用和類型檢查。注意:在使用別名前必須定義結構體,別名在程式中必須唯一且僅在其宣告的作用域內有效。

Java 中的變數期望值異常可以透過以下方法解決:初始化變數;使用預設值;使用 null 值;使用檢查和賦值;了解局部變數的作用域。

JavaScript 閉包的優點包括維持變數作用域、實作模組化程式碼、延遲執行和事件處理;缺點包括記憶體洩漏、增加了複雜性、效能開銷和作用域鏈影響。

C++ 中的 #include 預處理器指令將外部來源檔案的內容插入到目前原始檔案中,以複製其內容到目前原始檔案的相應位置。主要用於包含頭文件,這些頭文件包含程式碼中所需的聲明,例如 #include <iostream> 是包含標準輸入/輸出函數。

C++智慧指標的生命週期:建立:分配記憶體時建立智慧指標。所有權轉移:透過移動操作轉移所有權。釋放:智慧指標離開作用域或被明確釋放時釋放記憶體。物件銷毀:所指向物件被銷毀時,智慧型指標成為無效指標。

可以。 C++ 允許函數巢狀定義和呼叫。外部函數可定義內建函數,內部函數可在作用域內直接呼叫。巢狀函數增強了封裝性、可重複用性和作用域控制。但內部函數無法直接存取外部函數的局部變量,且傳回值類型需與外部函數宣告一致,內部函數不能自遞歸。

JavaScript 中,this 的指向類型有:1. 全域物件;2. 函數呼叫;3. 建構函式呼叫;4. 事件處理程序;5. 箭頭函數(繼承外層 this)。此外,可以使用 bind()、call() 和 apply() 方法明確設定 this 的指向。

在 Vue 中,let 和 var 宣告變數時在作用域上存在差異:作用域:var 具有全域作用域,let 具有區塊級作用域。區塊級作用域:var 不會建立區塊級作用域,let 建立區塊級作用域。重新宣告:var 允許在同一作用域內重新宣告變數,let 不允許。
