做者 | Jesksonhtml
來源 | 達達前端小酒館前端
1web
到底是什麼樣的題目讓我徒弟疑惑呢?讓咱們看看截圖先,來源於wx羣:面試
看看我是怎麼回答的:算法
function Foo() { getName = function () { alert (1); }; return this; } var getName; //只提高變量聲明 function getName() { alert (5);} //提高函數聲明,覆蓋var的聲明 Foo.getName = function () { alert (2);}; Foo.prototype.getName = function () { alert (3);}; getName = function () { alert (4);}; //最終的賦值再次覆蓋function getName聲明 getName(); //最終輸出4
看懂沒呢?沒看懂也別急哈:segmentfault
先讓咱們瞭解函數的定義:網絡
函數聲明,能夠先調用再聲明數據結構
dadaFn(); function dadaFn(){ console.log(dadaFn); }
/ 返回 f -> function function dadaFn() { console.log(dadaFn); }
let daDafn = function() { console.log("dada"); }; daDafn();
let fn = function() { console.log(111); } fn(); //111 VM1188:2 111 undefined let daDafn = function() { console.log("dada"); } daDafn(); VM1197:2 dada undefined
let da = () => {}; console.log( da.prototype );
JavaScript prototype屬性,可讓你向對象添加屬性和方法:函數
格式:學習
object.prototype.name = value;
function dada (name,age) { this.name = name; this.age = age; } var dashu = new dada("dashucoding", 13); dada.prototype.job = null; dashu.job = it; console.log(dashu.jog);
輸出結果:
it
let da1 = new Function('a', 'b'); da1(1,2);
let da1 = new Function('a', 'b'); da1(1,2); VM65:3 Uncaught ReferenceError: b is not defined at eval (eval at <anonymous> (local-ntp.html:1), <anonymous>:3:1) at <anonymous>:3:1 (anonymous) @ VM65:3 (anonymous) @ VM64:3 let fn1 = new Function('a', 'b', 'console.log(a * b)'); fn1(1, 2); //2 VM69:3 2 undefined
預解析,變量提高的概念:
function Foo() { getName = function () { console.log (1); }; return this; } Foo.getName = function () { console.log (2);}; Foo.prototype.getName = function () { console.log (3);}; var getName = function () { console.log (4);}; function getName() { console.log (5);} //請寫出如下輸出結果: Foo.getName(); getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName(); VM243:5 2 VM243:7 4 VM243:2 1 VM243:2 1 VM243:5 2 VM243:6 3 VM243:6 3
//答案: Foo.getName();//2 getName();//4 Foo().getName();//1 getName();//1 new Foo.getName();//2 new Foo().getName();//3 new new Foo().getName();//3
變量定義提高,this指針指向,運算符優先級
原型、繼承、全局變量污染、對象屬性及原型屬性優先級
在JavaScript中,prototype對象是實現面向對象的一個重要機制。
每一個函數就是一個對象(Function),函數對象都有一個子對象 prototype對象,類是以函數的形式來定義的。prototype表示該函數的原型,也表示一個類的成員的集合。
經過new建立一個類的實例對象的時候,prototype對象的成員都成爲實例化對象的成員。
一、該對象被類所引用,只有函數對象纔可引用;
二、在new實例化後,其成員被實例化,實例對象方可調用。
同時,函數是一個對象,函數對象若直接聲明成員,不用被實例化便可調用。
prototype 屬性使您有能力向對象添加屬性和方法。
構造函數的簡單介紹
function Person(){ this.name = 'dada'; } var boy = new Person(); console.log(boy.name); //'dada' VM254:5 dada undefined
爲了解決構造函數的對象實例之間沒法共享屬性的缺點,js提供了prototype屬性。
js中每一個數據類型都是對象(除了null和undefined)。
每一個對象都繼承自另一個對象,後者稱爲「原型」(prototype)對象,只有null除外,它沒有本身的原型對象。
原型對象上的全部屬性和方法,都會被對象實例所共享。
經過構造函數生成對象實例時,會將對象實例的原型指向構造函數的prototype屬性。
每個構造函數都有一個prototype屬性,這個屬性就是對象實例的原型對象。
原型對象的屬性不是對象實例的屬性。
對於對象實例來講,prototype是對象實例的原型對象。
因此prototype便是屬性,又是對象。
原型鏈:原型鏈主要用於繼承,每一個對象都有一個proto屬性指向其構造函數的原型對象,當訪問對象的屬性和方法時,會先在對象自身進行查找,若是不存在,則沿着proto屬性向上一級查找,直到沒找到返回 undefined,這樣的查找過程,稱之爲原型鏈。
原型鏈,請找我文章:一篇文章帶你瞭解JavaScript中的變量,做用域,和內存問題。
function Foo() { getName = function () { console.log (1); }; return this; } Foo.getName = function () { console.log (2);}; Foo.prototype.getName = function () { console.log (3);}; var getName = function () { console.log (4);}; function getName() { console.log (5);} //請寫出如下輸出結果: Foo.getName(); // 2
看代碼,先定義一個Foo()的函數,以後爲Foo建立一個叫getName的靜態屬性,用來存儲一個匿名的函數,以後爲Foo的原型對象,新建立了一個叫getName的匿名函數。
var getName = function () { console.log (4);}; function getName() { console.log (5);}
而後經過函數變量表達式,建立一個getName的匿名函數,而後由經過函數變量表達式,建立一個getName的函數。
最後一個是聲明一個叫getName的函數。
Foo.getName(); // 2
這個不用說就是訪問Foo()函數上存儲的靜態屬性,答爲2。
下一個問:
getName(); Foo().getName(); getName(); new Foo.getName(); new Foo().getName(); new new Foo().getName();
getName(); 的答案呢? // 5 function Foo() { getName = function () { console.log (1); }; return this; } 這裏要分開理解看 Foo.getName = function () { console.log (2);}; Foo.prototype.getName = function () { console.log (3);}; var getName = function () { console.log (4);}; function getName() { console.log (5);}
function Foo() { getName = function () { alert (1); }; return this; } var getName; //只提高變量聲明 function getName() { alert (5);} //提高函數聲明,覆蓋var的聲明 Foo.getName = function () { alert (2);};
getName = function () { alert (4);}; //最終的賦值再次覆蓋function getName聲明 getName(); //最終輸出4
var getName 只提高變量聲明
function getName 函數聲明,覆蓋var的聲明
直接調用getName()函數,就是訪問當前上文做用域內的叫getName的函數
這樣var getName提高,函數總體提高到上面了,那麼就剩下getName結果爲4的那個了。
一個是變量做用域問題,一個是this指向問題。
Foo().getName();
第一個Foo()函數:
function Foo() { getName = function() { console.log('1'); } }
即Foo().getName()中
先執行Foo()函數,而後調用Foo函數返回的返回值對象的getName屬性函數。
getName(); // 函數 1
至關於window.getName(),由於這個變量被Foo函數執行時修改了,結果一樣爲1。
new Foo.getName();
點 . 的優先級高於new操做,等價於:
new (Foo.getName)(); // 將getName函數做爲了構造函數來執行 // 2
new Foo().getName(); // 3 // 運算符優先級括號高於new 等價於 (new Foo()).getName()
先執行Foo函數,此時做爲構造函數,有返回值。
如有返回值則檢查其返回值是否爲引用類型
若返回值是引用類型,則實際返回值爲這個引用類型。
價於 (new Foo()).getName() # ``` ![file](https://graph.baidu.com/resource/2224fbd71c4d3b8c9599901577294998.png)
new new Foo().getName();
new ((new Foo()).getName)();
// 3
## ❤️ 不要忘記留下你學習的腳印 [點贊 + 收藏 + 評論] 做者Info: > 【做者】:Jeskson > 【原創公衆號】:達達前端小酒館。 > 【福利】:公衆號回覆 「資料」 送自學資料大禮包(進羣分享,想要啥就說哈,看我有沒有)! > 【轉載說明】:轉載請說明出處,謝謝合做!~ 大前端開發,定位前端開發技術棧博客,PHP後臺知識點,web全棧技術領域,數據結構與算法、網絡原理等通俗易懂的呈現給小夥伴。謝謝支持,承蒙厚愛!!! ---- 若本號內容有作得不到位的地方(好比:涉及版權或其餘問題),請及時聯繫咱們進行整改便可,會在第一時間進行處理。 ---- ## 請點贊!由於大家的贊同/鼓勵是我寫做的最大動力! ### 歡迎關注[達達](https://blog.csdn.net/qq_36232611)的CSDN! **這是一個有質量,有態度的博客**