1 預解析-Hoisting函數
■變量提高oop
變量提高,很簡單,就是把變量提高提到函數的top的地方。我麼須要說明的是,變量提高 只是提高變量的聲明,並不會把賦值也提高上來。this
一般,各種文章和JavaScript相關的書籍都聲稱:「不論是使用var關鍵字(在全局上下文)仍是不使用var關鍵字(在任何地方),均可以聲明一個變量」。請記住,這是錯誤的概念:spa
任什麼時候候,變量只能經過使用var關鍵字才能聲明。prototype
上面的賦值語句:code
a = 10;
這僅僅是給全局對象建立了一個新屬性(但它不是變量)。「不是變量」並非說它不能被改變,而是指它不符合ECMAScript規範中的變量概念,因此它「不是變量」(它之因此能成爲全局對象的屬性,徹底是由於VO(globalContext) === global,你們還記得這個吧?)。orm
■函數提高 對象
函數類型 | 提高能否 | 函數名有無 | 局部做用域使用與否 |
函數申明方式 |
YES | 必須有 | YES |
函數表達式方式 |
NO | 無關緊要 | YES |
函數構造器方式 |
NO | NO | NO |
◆函數申明方式(函數調用在函數申明以前,依然能夠調用)ip
function myTest(){ foo(); function foo(){ alert("我來自 foo"); } } myTest();
◆函數表達式方式(函數調用在函數表達式以前,不能調用.調用後⇒×TypeError foo is not a function)原型鏈
function myTest(){ foo(); var foo =function foo(){ alert("我來自 foo"); } } myTest();
◆函數構造器方式(不使用局部做用域)
var y = "global"; function constructFunction() { var y = "local"; //Function()構造函數 //不使用局部做用域 return new Function("return y;"); } function constFunction() { var y = "local"; //函數直接量 var f = function () { //使用局部做用域 return y; }; return f; } //顯示 global,由於Function()構造函數返回的函數並不使用局部做用域 alert(constructFunction()()); //顯示 lobal,由於函數直接量返回的函數並使用局部做用域 alert(constFunction()());
■函數申明和變量申明的關係和影響
function a(x) { x * 2; } var a; alert(a);
遇到同名的函數聲明,VO不會從新定義,因此這時候全局的VO應該是以下這樣的:
VO(global) = {
a: 引用了函數聲明「a」
}
而執行a的時候,相應地就彈出了函數a的內容了。
2 hasOwnProperty函數
hasOwnProperty是Object.prototype的一個方法,它但是個好東西,他能判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,由於hasOwnProperty 是 JavaScript 中惟一一個處理屬性可是不查找原型鏈的函數。
// 修改Object.prototype Object.prototype.bar = 1; var foo = {goo: undefined}; foo.bar; // 1 'bar' in foo; // true foo.hasOwnProperty('bar'); // false foo.hasOwnProperty('goo'); // true
只有 hasOwnProperty 能夠給出正確和指望的結果,這在遍歷對象的屬性時會頗有用。 沒有其它方法能夠用來排除原型鏈上的屬性,而不是定義在對象自身上的屬性。
但有個噁心的地方是:JavaScript 不會保護 hasOwnProperty 被非法佔用,所以若是一個對象碰巧存在這個屬性,就須要使用外部的 hasOwnProperty 函數來獲取正確的結果
var foo = { hasOwnProperty: function() { return false; }, bar: 'Here be dragons' }; foo.hasOwnProperty('bar'); // 老是返回 false // 使用{}對象的 hasOwnProperty,並將其上下爲設置爲foo {}.hasOwnProperty.call(foo, 'bar'); // true
當檢查對象上某個屬性是否存在時,hasOwnProperty 是惟一可用的方法。同時在使用 for in loop 遍歷對象時,推薦老是使用 hasOwnProperty 方法,這將會避免原型對象擴展帶來的干擾,咱們來看一下例子:
// 修改 Object.prototype Object.prototype.bar = 1; var foo = {moo: 2}; for(var i in foo) { console.log(i); // 輸出兩個屬性:bar 和 moo }
咱們沒辦法改變for in語句的行爲,因此想過濾結果就只能使用hasOwnProperty 方法,代碼以下:
// foo 變量是上例中的 for(var i in foo) { if (foo.hasOwnProperty(i)) { console.log(i); } }
這個版本的代碼是惟一正確的寫法。因爲咱們使用了 hasOwnProperty,因此此次只輸出 moo。若是不使用 hasOwnProperty,則這段代碼在原生對象原型(好比 Object.prototype)被擴展時可能會出錯。
總結:推薦使用 hasOwnProperty,不要對代碼運行的環境作任何假設,不要假設原生對象是否已經被擴展了。
3 this
3.1在全局代碼中,this始終是全局對象自己,這樣就有可能間接的引用到它了。
3.2在一般的函數調用中,this是由激活上下文代碼的調用者來提供的,即調用函數的父上下文(parent context )。this取決於調用函數的方式。
如下是經典案例↓
foo() { alert(.bar); } x = {bar: 10}; y = {bar: 20}; x.test = foo; y.test = foo; x.test(); y.test();