JavaScript 原型鏈 OOP(二)

 
原型對象 `prototype`
-  原型對象的全部屬性和方法,都能被實例對象共享;
 
JavaScript 經過構造函數生成新對象,所以構造函數能夠視爲對象的模板。實例對象的屬性和方法,能夠定義在構造函數內部。
 
function Cat (name, color) {
this.name = name;
this.color = color;
}

var cat1 = new Cat('小明', '白色');

cat1.name // '小明'
cat1.color // '白色'

 

構造函數缺點:

- 一個構造函數的多個實例之間,沒法共享屬性,從而形成對系統資源的浪費。

 

解決方法,就是 JavaScript 的 原型對象`prototype`,由於原型對象的全部屬性和方法,都能被實例對象共享。
function Cat (name, color) {
this.name = name;
}
Cat.prototype.color ="白色";
}
var cat1 = new Cat('巧克力');
var cat2 = new Cat('布丁');
cat1.color //白色
cat2.color//白色
 JavaScript規定,每一個函數都有一個`prototype`屬性,指向一個對象。
- 對於構造函數來講,生成實例的時候,該屬性會自動成爲實例對象的原型。
- 實例對象自身就有某個屬性或方法,它就不會再去原型對象尋找這個屬性或方法。
function f() {}
typeof f.prototype // "object"

 

每一個 JS 對象都有 ` __proto__` 屬性,這個屬性能夠訪問到 原型(` [[prototype]]`) 內部屬性。這個屬性在如今來講已經不推薦直接去使用它了。

 

  原型鏈

 - 任何對象,均可以充當其餘對象的原型;原型對象也有本身的原型。
 - 對象到原型,再到原型的原型,一層層向上找到`Object.prototype` 造成原型鏈。

 

能夠說 基本上全部對象都繼承了`Object.prototype`的屬性;而 `Object.prototype` 的原型是 `null`
經過 ` getPrototypeOf` 方法返回參數對象原型
Object.getPrototypeOf(Object.prototype) //null

 

 讀取對象屬性時,引擎會先在自身屬性上查找,沒有就查找原型,一級級向上查找,若是到`Object.prototype`仍是沒有,則返回`undefined`。
**一級級向上,對性能有影響,尋找的層級越多,性能影響越大**
 
**原型鏈:**

 
- 實例 F1 經過`__proto__` 訪問對應構造函數的原型 -> `FOO.prototype`
 
- 函數原型再經過`__proto__` 訪問Object的原型 -> `Object.prototype`
 
- Object的原型的`__proto__` 指向 `null`
 
- 構造函數 `Foo.prototype` 經過`constructor`訪問構造函數自己
 
- `Object.constructo` 指向 `Function`
 
- `Function.constructo` 指向 自己
 
- `Function.__proto__` 指向一個匿名函數
 
- 每一個構造函數經過 `prototype` 訪問原型
**只有函數才擁有`prototype`屬性,基本上全部函數都有這個屬性**
let fun = Function.prototype.bind()
當聲明一個函數時自動建立 `prototype` 屬性,
這個屬性的值是一個對象(也就是原型),且只有一個屬性 `constructor`
 

 `constructor`

`prototype` 有一個屬性 `constructor`,默認指向原型所在的構造函數
function Fn (){}
var f = new Fn ();
f.constructor == Fn //true
f.constructor == Function //false


//能夠從實例對象新建另外一個實例
var b =new f.constructor();
b.constructor == Fn //true
`constructor `是一個公有且不可枚舉的屬性。一旦咱們改變了函數的 prototype ,那麼新對象就沒有這個屬性了,若是修改了原型對象,通常會同時修改constructor屬性,防止引用的時候出錯。
function A(){}
console.log(A.prototype) // {constructor: ƒ}constructor: ƒ A()__proto__: Object
A.prototype="a"
console.log(A.prototype) //"a"

 

constructor做用:

- 讓實例對象知道是什麼函數構造了它,能夠得知某個實例對象,是哪個構造函數產生的。
- 若是想給某些類庫中的構造函數增長一些自定義的方法,就能夠經過 xx.constructor.method 來擴展

 

 \_\_proto\_\_

基本上每一個對象都有的隱式原型屬性,指向建立該對象的構造函數的原型,實際指向`[[prototype]]`, 內部屬性,咱們並不能訪問到,因此使用 _proto_ 來訪問。
console.log({})
//__proto__: Objectconstructor: ƒ Object()hasOwnProperty: ....

 

當咱們使用 new 操做符時,生成的實例對象擁有了 `__proto__`屬性。

function Foo() {}
// 這個函數是 Function 的實例對象
// function 就是一個語法糖
// 內部調用了 new Function(...)
const a =1;
const fn = new Function("console.log(a)") // Function 的this始終指向 全局對象,除非手動改變this指向
fn()//1

 

- 全部對象均可以經過原型鏈最終找到 Object.prototype ,雖然 Object.prototype 也是一個對象,可是這個對象卻不是 Object 創造的,而是引擎本身建立了 `Object.prototype` 。
能夠這樣說,全部實例都是對象,可是對象不必定都是實例。

 

-首先引擎建立了 Object.prototype ,而後建立了 Function.prototype ,而且經過__proto__ 將二者聯繫了起來。

 

- Function.prototype 之後纔有了 function Function() ,而後其餘的構造函數都是 function Function() 生成的。

 

- 函數經過 `new Function()` 生成, 不是全部函數都是 `new Function() `產生的。 
 
總結:
> 1. Object 是全部對象的爸爸,全部對象均可以經過__proto__ 找到它
 
> 2. Function 是全部函數的爸爸,全部函數均可以經過__proto__ 找到它
 
> 3. Function.prototype 和 Object.prototype 是兩個特殊的對象,他們由引擎來建立
 
> 4. 除了以上兩個特殊對象,其餘對象都是經過構造器 new 出來的
 
> 5. 函數的 prototype 是一個對象,也就是原型
 
對象的__proto__ 指向原型,__proto__將對象和原型鏈接起來組成了原型鏈



   JavaScript 對象繼承 OOP (三)


html

相關文章
相關標籤/搜索