預解釋的原理
- 預解釋的不同機制
var
的預解釋機制function
的預解釋機制- 預解釋機制
- 面試題練習
預解釋的的不同機制
預解釋也叫預聲明,是提前解釋聲明的意思;預解釋是針對變量和函數來說的;但是變量和function的的預解釋是兩套不同的機制;
- 當瀏覽器加載我們的HTML頁面的時候,首先會提供一個供JS代碼執行的環境->全局作用域global(瀏覽器中的全局作用域,也叫頂級作用域是window)
- JS中的內存空間分為兩種:棧內存、堆內存
- 棧內存;提供JS代碼執行的環境,存儲基本數據類型的值;->全局作用域或者私有的作用域其實都是棧內存;
- 堆內存;存儲引用數據類型的值(對象是把屬性名和屬性值儲存進去,函數是把函數體內的代碼當做字符串儲存進去)
- 在當前的作用域中,JS代碼執行之前,瀏覽器首先會默認的把所有代var和function的進行提前的聲明或者定義,->“預解釋”(也叫變量提升)
var
的預解釋機制
var a=1
-
1、代碼運行之前,先掃描有沒有帶
var
關鍵字的變量名,有的話,為這個變量名在內存里開一個空間;這時候變量名a
是不代表任何值的;用undefined
來表示;undefined
是一個標識符/記號,表示找不到這個變量名所代表的數據;不存在的意思;這個階段叫變量的聲明; -
2、當代碼運行的時候,則給數據1開闢一個內存空間;
-
3、讓數據1和變量名a綁定在一起;變量類型指的就是數據類型;按照js語言的原理來說變量類型有undefined類型;但是數據類型是沒有undefined這種數據類型的;只有”undecided”這種字符串類型(字符串類型是數據類型的一種);同理也沒有unll這個數據類型,但是有”null”這種字符串類型;
var num; //1、聲明(declare):var num; ->告訴瀏覽器在當前作用域中有一個num的變量了,如果一個變量只是聲明了但是沒有賦值,默認的值是undefined console.log(num);//->undefined num = 12; //2、定義(defined):num=12; ->給我們的變量進行賦值 console.log(num);//->12 //變量提前使用的話,就是undefined console.log(testStr);//undefined var testStr="22222222"
function
關鍵字的預解釋步驟
function fn(){……}
在代碼執行之前,把所有的帶function關鍵字的腳本都掃描一遍,然後定義變量;並且同時給變量賦值;
-
1、函數的定義只是保存一些字符串;預解釋的時候在內存里保存
fn
大括號裏面的字符串; -
2、代碼運行時候,讀到
fn()
時候,這個時候就是函數的運行;函數的運行,會先開闢一個堆內存把字符串當做代碼在堆內存中再次運行,函數產生的作用域內還會再進行預解釋和代碼運行;函數如果多次執行;會產生多個作用域;但是產生的多個作用域裏面的內容都是相互獨立的;互相沒有關係;(在原型和原型鏈時候再仔細研究原理;)
fn(100,200);//->可以在上面執行,因為預解釋的時候聲明+定義就已經完成了 function fn(num1, num2) { var total = num1 + num2; console.log(total); }
總結
- 1、
var
和function
關鍵字的在預解釋的時候操作還是不一樣的var
-> 在預解釋的時候只是提前的聲明了這個變量,只有當代碼執行的時候才會完成賦值操作function
-> 在預解釋的時候會提前的把聲明加定義都完成了(在代碼執行的時候遇到定義的代碼直接的跳過)
- 2、預解釋只發生在當前的作用域下,例如:開始只對window下的進行預解釋,只有函數執行的時候才會對函數中的進行預解釋;
[重要]剛開始只對window下的進行預解釋,fn函數中目前存儲的都是字符串,所以var total沒啥實際的意義,所以不進行預解釋 -> “預解釋是發生在當前作用域下的”
綜合題;
console.log(obj);//->undefined
var obj = {name: "xie", age: 25};
function fn(num1, num2) {//代碼執行到這一行的時候直接的跳過這一塊的代碼,因為在預解釋的時候我們已經完成了聲明加定義
var total = num1 + num2;
console.log(total);
}
var num1 = 12;
fn(num1, 100);//執行fn,把全局變量num1的值賦值給形參num1,把100賦值給形參num2
-
下面是一個預解釋思路
var a, b = 0, fn = function () { var a = b = 2; }; fn(); console.log(a, b);
把上面解析成下面就好理解了
var a;
window.b = 0;
window.fn = function () {
//var a = b = 2;
var a = 2;//a是私有的和全局沒關係
b = 2;//b是全局的
};
fn();//window.fn()
console.log(a, b);//undefined 2
預解釋機制
-
1、不管條件是否成立都要進行預解釋
console.log(a);//->undefined if (!!("a" in window)) {//"a" in window -> true var a = "xie"; } console.log(a);//->xie
例子中的if是不成立的,預解釋的時候,碰到非
functon
內的var
,都會聲明,無論你寫在if else 還是別的判斷里; 假設if語句起作用的話,那麼第一次log(a)
的時候,就會報錯了(沒有聲明的變量,是不能直接用的,除非typeof
),而聲明並且沒有賦值的表現才是undefined
;假設不成立; 最開始總結的預解釋步驟:代碼運行之前,先掃描有沒有帶var關鍵字的變量名,有的話,為這個變量名,在內存里開一個空間;預解釋是發生在代碼執行前的,所以if根本阻擋不了預解釋; -
2、預解釋只發生在”=“的左邊,只把左邊的進行預解釋,右邊的是值是不進行預解釋的
匿名函數之函數表達式:把函數定義的部分當做值賦值給一個變量或者元素的事件
fn1();//->undefined() Uncaught TypeError: fn is not a function JS中只有函數可以執行 && JS上面的代碼如果報錯了,在不進行任何的特殊處理情況下我們下面的代碼都不在執行了
var fn1 = function () {
console.log("ok");
};
fn1();
//預解釋的時候:fn=xxxfff000
fn2();//->"ok"
function fn2() {
console.log("ok");
}
fn2();//->"ok"
預解釋的時候:var fn1 = function()...
->fn
的默認值是undefined
;這裏即使有function
,也是不能進行預解釋的
-
3、函數體中return下面的代碼都不在執行了,但是下面的代碼需要參加預解釋;而return後面的東西是需要處理的,但是由於它是當做一個值返回的,所以不進行預解釋;
function fn() { console.log(total); return function sum() {};//return是把函數中的值返回到函數的外面,這裡是把function對應的內存地址返回的到函數的外面,例如:return xxxfff111;函數體中return下面的代碼都不在執行了 var total = 10; console.log(total); }
-
4、匿名函數的function在全局作用域下是不進行預解釋的;
匿名函數之自執行函數:定義和執行一起完成了;函數內的聲明,只是在函數內使用;
(function(num){
var testStr="test"+num;
console.log(num);
})(100);
console.log(testStr);// testStr is not defined
- 5、在預解釋的時候,如果遇到名字重複了,只聲明一次。 不重複的聲明,但是賦值還是要重複的進行的
預解釋:
var fn; 聲明
fn = xxxfff000; [聲明]不用了+定義
fn = xxxfff111; [聲明]不用了+定義
// ->fn=xxxfff111
var fn = 12;//window.fn=12
function fn() {//window.fn=function(){}
}
JS中作用域只有兩種:
- window全局作用域;
- 函數執行形成的私有作用域;
{name:“”}
if(){}
for(){}
while(){}
switch(){}
這些都不會產生作用域;
ES6可以用let
形成塊級作用域;http://www.cnblogs.com/snandy/archive/2015/05/10/4485832.html
面試題
// 涉及this的指向和閉包
var num = 20;
var obj = {
num: 37,
fn: (function (num) {
this.num *= 3; // window.num * 3 = 60
// num += 15;
var num = 45;
return function () {
this.num *= 4;
num += 20; // 調用父作用域的num (45+20)
console.log(num);
};
})(num), //->把全局變量num的值20賦值給了自執行函數的形參,而不是obj下的30,如果想是obj下的30,我們需要寫obj.num
};
var fn = obj.fn;
fn(); //->65 , 執行了第1次=> window.num = 240
obj.fn(); //->85 閉包(65+20) // 執行了第2次=> obj.num = 37*4 = 148
console.log(window.num, obj.num); // 240,148
本站聲明:網站內容來源於博客園,如有侵權,請聯繫我們,我們將及時處理
【其他文章推薦】
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※別再煩惱如何寫文案,掌握八大原則!
※教你寫出一流的銷售文案?
※超省錢租車方案
※廣告預算用在刀口上,台北網頁設計公司幫您達到更多曝光效益
※產品缺大量曝光嗎?你需要的是一流包裝設計!