網(wǎng)站都是什么軟件做的百度營(yíng)銷推廣
來講一講原型鏈
原型鏈只存在于函數(shù)之中
四個(gè)規(guī)則
1、引用類型,都具有對(duì)象特性,即可自由擴(kuò)展屬性。
2、引用類型,都有一個(gè)隱式原型 __proto__ 屬性,屬性值是一個(gè)普通的對(duì)象。
3、引用類型,隱式原型 __proto__ 的屬性值指向它的構(gòu)造函數(shù)的顯式原型 prototype 屬性值。
4、當(dāng)你試圖得到一個(gè)對(duì)象的某個(gè)屬性時(shí),如果這個(gè)對(duì)象本身沒有這個(gè)屬性,那么它會(huì)去它的隱式原型 __proto__(也就是它的構(gòu)造函數(shù)的顯式原型 prototype)中尋找。
四個(gè)知識(shí)點(diǎn)
- Object 是所有對(duì)象的爸爸,所有對(duì)象都可以通過 __proto__ 找到它
- Function 是所有函數(shù)的爸爸,所有函數(shù)都可以通過 __proto__ 找到它
- 函數(shù)的 prototype 是一個(gè)對(duì)象
- 對(duì)象的 __proto__ 屬性指向原型, __proto__ 將對(duì)象和原型連接起來組成了原型鏈
const obj = {};
const arr = [];
const fn = function() {}obj.__proto__ == Object.prototype // true
arr.__proto__ === Array.prototype // true
fn.__proto__ == Function.prototype // true
new 做了什么
var obj = new F();
// 做了什么
var obj = {};
obj.__proto__ = F.prototype;
F.call(obj);
第一行,我們創(chuàng)建了一個(gè)空對(duì)象obj;
第二行,我們將這個(gè)空對(duì)象的__proto__成員指向了F函數(shù)對(duì)象prototype成員對(duì)象;
第三行,我們將F函數(shù)對(duì)象的this指針替換成obj,然后再調(diào)用F函數(shù).
我們可以這么理解: 以 new 操作符調(diào)用構(gòu)造函數(shù)的時(shí)候,函數(shù)內(nèi)部實(shí)際上發(fā)生以下變化:
1、創(chuàng)建一個(gè)空對(duì)象,并且 this 變量引用該對(duì)象,同時(shí)還繼承了該函數(shù)的原型。
2、屬性和方法被加入到 this 引用的對(duì)象中。
3、新創(chuàng)建的對(duì)象由 this 所引用,并且最后隱式的返回 this.
prototype和__proto__
1. __proto__是每個(gè)對(duì)象都有的一個(gè)屬性,而prototype是函數(shù)才會(huì)有的屬性。
2. __proto__指向的是當(dāng)前對(duì)象的原型對(duì)象,而prototype指向的,是以當(dāng)前函數(shù)作為構(gòu)造函數(shù)構(gòu)造出來的對(duì)象的原型對(duì)象。
你的__proto__來自你構(gòu)造函數(shù)的prototype;所有對(duì)象字面量都是通過Object()構(gòu)造出來的,換言之,對(duì)象字面量__proto__ 屬性都指向Object.prototype
- prototype: 顯式原型
每一個(gè)函數(shù)在創(chuàng)建之后都會(huì)擁有一個(gè)名為prototype的屬性,這個(gè)屬性指向函數(shù)的原型對(duì)象。
通過Function.prototype.bind方法構(gòu)造出來的函數(shù)是個(gè)例外,它沒有prototype屬性
JavaScript中任意對(duì)象都有一個(gè)內(nèi)置屬性[[prototype]],在ES5之前沒有標(biāo)準(zhǔn)的方法訪問這個(gè)內(nèi)置屬性,但是大多數(shù)瀏覽器都支持通過__proto__來訪問。ES5中有了對(duì)于這個(gè)內(nèi)置屬性標(biāo)準(zhǔn)的Get方法Object.getPrototypeOf().
Object.prototype 這個(gè)對(duì)象是個(gè)例外,它的__proto__值為null
隱式原型指向創(chuàng)建這個(gè)對(duì)象的函數(shù)(constructor)的prototype
作用是什么:顯式原型的作用:用來實(shí)現(xiàn)基于原型的繼承與屬性的共享。
?
?
- __ proto__: 隱式原型
隱式原型的作用:構(gòu)成原型鏈,同樣用于實(shí)現(xiàn)基于原型的繼承。舉個(gè)例子,當(dāng)我們?cè)L問obj這個(gè)對(duì)象中的x屬性時(shí),如果在obj中找不到,那么就會(huì)沿著__proto__依次查找。
__proto__的指向:__proto__的指向到底如何判斷呢?根據(jù)ECMA定義 'to the value of its constructor’s "prototype" ' ----指向創(chuàng)建這個(gè)對(duì)象的函數(shù)的顯式原型。所以關(guān)鍵的點(diǎn)在于找到創(chuàng)建這個(gè)對(duì)象的構(gòu)造函數(shù),接下來就來看一下JS中對(duì)象被創(chuàng)建的方式,一眼看過去似乎有三種方式:(1)對(duì)象字面量的方式 (2)new 的方式 (3)ES5中的Object.create() 但是我認(rèn)為本質(zhì)上只有一種方式,也就是通過new來創(chuàng)建。為什么這么說呢,首先字面量的方式是一種為了開發(fā)人員更方便創(chuàng)建對(duì)象的一個(gè)語(yǔ)法糖,本質(zhì)就是 var o = new Object(); o.xx = xx;o.yy=yy; 再來看看Object.create(),這是ES5中新增的方法,在這之前這被稱為原型式繼承,
構(gòu)造函數(shù)的prototype和其實(shí)例的__proto__是指向同一個(gè)地方的,這個(gè)地方就叫做原型對(duì)象
Function和Object
構(gòu)造函數(shù)的prototype和其實(shí)例的__proto__是指向同一個(gè)地方的,咱們可以來驗(yàn)證一下
- 函數(shù)是Function構(gòu)造函數(shù)的實(shí)例
- 對(duì)象是Object構(gòu)造函數(shù)的實(shí)例
那Function構(gòu)造函數(shù)和Object構(gòu)造函數(shù)他們兩個(gè)又是誰(shuí)的實(shí)例呢?
- function Object()其實(shí)也是個(gè)函數(shù),所以他是Function構(gòu)造函數(shù)的實(shí)例
- function Function()其實(shí)也是個(gè)函數(shù),所以他也是Function構(gòu)造函數(shù)的實(shí)例,沒錯(cuò),他是他自己本身的實(shí)例
?
console.log(Function.prototype === Object.__proto__) // true
console.log(Function.prototype === Function.__proto__) // true
constructor和prototype是成對(duì)的,你指向我,我指向你
function fn() {}console.log(fn.prototype) // {constructor: fn}
console.log(fn.prototype.constructor === fn) // true
原型鏈
什么是原型鏈呢?其實(shí)俗話說就是:__proto__的路徑就叫原型鏈
原型繼承
說到原型,就不得不說補(bǔ)充一下原型繼承這個(gè)知識(shí)點(diǎn)了,原型繼承就是,實(shí)例可以使用構(gòu)造函數(shù)上的prototype中的方法
instanceof
作用:判斷B的prototype是否在A的原型鏈上
A instanceof B
【JS】圖解原型鏈相關(guān)練習(xí)題,帶你徹底搞懂原型鏈!!!(這可能是掘金畫原型鏈畫的最正的😃) - 掘金
第一題
主要坑是 f的構(gòu)造函數(shù)是 F F的構(gòu)造函數(shù)是Obj,
f的所有方法從以下找
f.__proto__ === F.protyotype F.__proto__ === obj.protyotype obj.proto=== null
F的所有方法從以下找
F.__proto__ === Function.protyotype Function.__proto__ === obj.protyotype obj.proto=== null
var F = function() {};Object.prototype.a = function() {console.log('a');
};Function.prototype.b = function() {console.log('b');
}var f = new F();f.a();
f.b();F.a();
F.b();
第二題
b的所有方法從以下找
b.__proto__ === A.protyotype A.proto=== obj.protyotype obj.proto=== null
c的所有方法從以下找
b.__proto__ === A.protyotype A.proto=== obj.protyotype obj.proto=== null
本體核心是每次new時(shí)使用的都是構(gòu)造函數(shù)最新的prototype ,老的構(gòu)造函數(shù)引用老的prototype 并不會(huì)被覆蓋
var A = function() {};
A.prototype.n = 1;
var b = new A();
A.prototype = {n: 2,m: 3
}
var c = new A();console.log(b.n);
console.log(b.m);console.log(c.n);
console.log(c.m);
第三題
函數(shù)的構(gòu)造函數(shù)一定是Function 對(duì)象的構(gòu)造函數(shù) 可能是obj 也可能是new Function
var foo = {},F = function(){};
Object.prototype.a = 'value a';
Function.prototype.b = 'value b';console.log(foo.a);
console.log(foo.b);console.log(F.a);
console.log(F.b);
第四題
new 的時(shí)候會(huì)函數(shù)內(nèi)this會(huì)重新賦值進(jìn)行覆蓋
function A() {}
function B(a) {this.a = a;
}
function C(a) {if (a) {this.a = a;}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;console.log(new A().a);
console.log(new B().a);
console.log(new C(2).a);