做者 | 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
複製代碼
看懂沒呢?沒看懂也別急哈:bash
先讓咱們瞭解函數的定義:網絡
函數聲明,能夠先調用再聲明數據結構
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://user-gold-cdn.xitu.io/2019/12/26/16f3e1e6c318279d?w=582&h=180&f=png&s=42906)
複製代碼
new new Foo().getName();
new ((new Foo()).getName)();
// 3
## ❤️ 不要忘記留下你學習的腳印 [點贊 + 收藏 + 評論]
做者Info:
> 【做者】:Jeskson
> 【原創公衆號】:達達前端小酒館。
> 【福利】:公衆號回覆 「資料」 送自學資料大禮包(進羣分享,想要啥就說哈,看我有沒有)!
> 【轉載說明】:轉載請說明出處,謝謝合做!~
大前端開發,定位前端開發技術棧博客,PHP後臺知識點,web全棧技術領域,數據結構與算法、網絡原理等通俗易懂的呈現給小夥伴。謝謝支持,承蒙厚愛!!!
----
若本號內容有作得不到位的地方(好比:涉及版權或其餘問題),請及時聯繫咱們進行整改便可,會在第一時間進行處理。
----
## 請點贊!由於大家的贊同/鼓勵是我寫做的最大動力!
### 歡迎關注[達達](https://blog.csdn.net/qq_36232611)的CSDN!
**這是一個有質量,有態度的博客**
![前端技術棧](https://user-gold-cdn.xitu.io/2019/12/26/16f3e1e6ea92d021?w=258&h=258&f=png&s=43370)複製代碼