先來一個小測試javascript
環境:對象 person1 有一個__proto__屬性,建立它的構造函數是 Person,構造函數的原型對象是 Person.prototype
html
問題:java
答案:
第一題:
由於 person1.__proto__==person1 的構造函數 .prototype數組
由於 person1的構造函數 ===Personbash
因此 person1.__proto__ === Person.prototype函數
第二題:
由於person.__proto__===Person的構造函數 .prototype
由於Person的構造函數===Function
因此person.__proto__===Function.prototype測試
第三題:
Person.prototype 是一個普通對象,咱們無需關注它有哪些屬性,只要記住它是一個普通對象。
由於一個普通對象的構造函數 === Object
因此Person.prototype.__proto__===Object.prototypethis
第四題,參照第二題,由於 Person 和 Object 同樣都是構造函數spa
第五題:
Object.prototype對象也有proto屬性,但它比較特殊,爲 null 。由於 null 處於原型鏈的頂端,這個只能記住。Object.prototype.
Object.prototype.__proto__=== null
prototype
先看下圖
分析一下:
能夠看出原型鏈的覺得就是:原型鏈經過prototype和__proto__來完成原型的查找。從一個實例對象往上找構造這個實例的相關的原型對象,而後相關聯的原型對象再往上找創造它的原型對象,一直到object.prototype原型對象終止。
經過原型鏈,能夠進行數據共享,也就是找到原型對象,原型對象的方法被不一樣的實例所共有。
查找一個實例中的一個方法或者屬性,若是這個這個實例沒有找到,就會經過__proto__往上一級找原型對象,若是還找不到就會再往上找,直到object.proototype位置,若是還找不到,就會返回這個屬性或者方法沒有找到或者沒有定義。若是在中間任何一個原型對象找到了,那麼返回這個屬性和方法,就不會再往上尋找。
強調一下只有函數纔會有有prototype,對象是沒有prototype的,只有實例對象有 __proto__
解釋一下爲何函數也會有__proto__
從圖中能夠看到,函數name()也是函數Function的原型對象,因此函數也即對象。
萬物皆對象!但對象也是有區別的。分爲普通對象和函數對象,Object 、Function 是 JS 自帶的函數對象。
看下面例子
//a.js
(function()
{
var secret = ["aaa","bbb"];
secret.forEach();
})();
複製代碼
//b.html
<body>
<script>
Array.prototype.forEach = function() {
var result = 'result: ';
for(var i=0,length = this.length; i<length;i++){
result += this[i];
result += ''
}
document.write(result);
}
</script>
<script src="./a.js"></script>
</body>
複製代碼
運行結果:
在a.js中聲明瞭一個數組 secret ,而後該數組調用了屬於 Array.prototype的forEach方法,以下
可是,在調用js文件以前,js代碼中將 Array. prototype.forEach 方法進行了重寫,而prototype鏈爲 secret -> Array.prototype ->object.prototype,secret中無 foreach 方法,因此就會向上檢索,就找到了 Array.prototype 而forEach方法已經被重寫過了,因此會執行輸出。
這就是原型鏈污染。很明顯,原型鏈污染就是:在咱們想要利用的代碼以前的賦值語句若是可控的話,咱們進行 __proto__ 賦值,以後就能夠利用代碼了。