理清原型物件、 例項物件、建構函式

網友咚咚發表於2020-03-15

1.物件是什麼

物件導向程式設計(OOP):具有靈活性,程式碼可複用性,高度模組化等特點。 1.物件是單個實物的抽象。 2.物件是一個容器,封裝了對應屬性和方法。 屬性是物件的狀態,方法是物件的行為。

2.建構函式

需要一個模版(表示一類實物的共同特徵),讓物件生成。 類(class)就是物件的模版。 js不是基於類的,而是基於建構函式(constructor)和原型鏈(prototype)。

建構函式特點: 1.函式體內使用this關鍵字,代表了所要生成的物件例項。 2.生成物件,必須使用new 關鍵字例項化。

Dog是建構函式,為了與普通函式區別建構函式的名字的第一個字母通常大寫

  function Dog(name,age) {
// name和age就是當前例項化物件的屬性
this.name = name
this.age = age
}
var dog1 = new Dog("小黑",5)
console.log('Dog 建構函式',Dog);
console.log('dog1 例項物件',dog1);
複製程式碼

控制檯列印:

3.instanceof 用法

instanceof運算子測試建構函式的prototype屬性是否出現在物件的原型鏈中的任何位置

如果忘記寫new關鍵字了,我們可以用instanceof 運算子來解決。

 function Person(name) {
// 判斷this是否指向了當前的例項
if (this instanceof Person) {
// this指向了當前的例項,外部使用了關鍵字new
this.name = name
}else {
// this指向window,外部沒有使用關鍵字new
return new Person(name)
}
}
var p1 = new Person("咚咚")
var p2 = new Person("鏘鏘")
console.log("p1",p1);
console.log("p2",p2);
複製程式碼

控制檯列印:

4.new關鍵字原理

new 運算子建立一個使用者定義的物件型別的例項或具有建構函式的內建物件的例項。

new 關鍵字會進行如下的操作:

1.建立一個空物件,作為將要返回的物件例項 2.將這個空的物件原型物件,指向了建構函式的prototype屬性物件 3.將這個例項物件的值賦值給函式內部的this關鍵字 4.執行建構函式內的程式碼。 5.如果該函式沒有返回物件,則返回this。

  function Person(name) {
this.name = name
}
var p1 = new Person('咚咚')
console.log("p1:",p1);
console.log("p1.__proto__ === Person.prototype:",p1.__proto__ === Person.prototype);
console.log("Person.prototype:",Person.prototype);
複製程式碼

控制檯列印:

圖解:

5.constructor屬性

每個物件在建立時都會自動擁有一個建構函式constructor屬性

function Person(name) {
this.name = name
}
var p1 = new Person("咚咚")
console.log("p1:",p1);
// constructor繼承自原型物件,指向了建構函式的引用
console.log("Person.prototype:",Person.prototype);
console.log("p1.constructor === Person:",p1.constructor === Person);
複製程式碼

控制檯列印:

6.使用建構函式建立物件的利與弊

:例項物件具有相同的屬性和方法,方便呼叫。 :例項物件呼叫了相同的方法,佔用了記憶體空間,浪費系統資源。

  function Person(name) {
this.name = name
this.sayName = function () {
console.log(this.name);
}
}
var p1 = new Person("Tom")
var p2 = new Person("Jack")
console.log("p1:",p1);
console.log("p2:",p2);
複製程式碼

控制檯列印: image-20200315145202164

7.原型物件

原型物件:Foo.prototype。 例項物件:f1 就是例項物件,每個例項物件( f1 )都有一個私有屬性(稱之為 proto )指向它的建構函式的原型物件(prototype ),每一個例項物件都有一個constructor屬性,這個constructor是通過繼承關係繼承來的,它指向了當前的建構函式Foo。 建構函式:用來初始化新建立物件的函式,Foo是建構函式,自動給建構函式賦予一個prototype屬性,該屬性指向了例項物件的原型物件。

  function Foo() {}
Foo.prototype.showName = function () {
console.log('咚咚');
}
var f1 = new Foo()
var f2 = new Foo()
console.log("f1.showName():",f1);
console.log("f2.showName():",f2);
f1.showName()
f2.showName()
複製程式碼

控制檯列印: ![image-20200315151518716](https://tva1.sinaimg.cn/large/00831rSTgy1gcuqzypnqzj30bh062jrp.jpg)

8.搞清它們三者之間的關係

  function Foo() {}
var f1 = new Foo()
console.log("f1",f1);
console.dir(Foo);
console.log("Foo.prototype === f1.__proto__:",Foo.prototype === f1.__proto__);
console.log("f1.__proto__.__proto__:",f1.__proto__.__proto__);
複製程式碼

控制檯列印:

圖解:

image-20200315155028181
image-20200315155028181

9.prototype屬性的作用

js繼承機制:通過原型物件實現繼承。 原型物件的作用就是定義所有例項物件共享的屬性和方法。

  function Foo(){}
Foo.prototype.name = "咚咚"
var f1 = new Foo()
var f2 = new Foo()
console.log(f1.name);
console.log(f2.name);
Foo.prototype.name = "鏘鏘"
console.log(f1.name);
console.log(f2.name);
複製程式碼

控制列印: image-20200315160020204

10.原型鏈

js規定:所有的物件都有自己的原型物件。

原型鏈:物件的原型=>原型的原型=>原型的原型的原型=====>null

1.根據原型鏈查詢,如果一層一層往上查詢,所有的物件的原型最終都可以尋找得到Object.prototype,Object建構函式的prototype 2.所有的物件都繼承了Object.prototype上的屬性和方法 3.讀取屬性和方法的規則:js引擎會先尋找物件本身的屬性和方法,如果找不到,就到它的原型物件去找,如果還是找不到,就到原型的原型去找,如果直到最頂層的Object.prototype還是找不到, 如果物件和它的原型,都定製了同名的屬性,那麼優先讀取物件自身屬性,這也叫覆蓋

  function Person(name) {
this.name = name
this.showName= function () {
console.log('咚咚');
}
}
Person.prototype.showName = function(){
console.log(this.name);
}
var p1 = new Person("小紅")
var p2 = new Person("小明")
p1.showName()
p2.showName()
複製程式碼

控制檯列印:

image-20200315161712900
image-20200315161712900

修改原型物件的注意點

  • 一旦我們修改建構函式的原型物件,為了防止引用出現問題,同時也要修改原型物件的constructor屬性。
  function MyArray(){}
MyArray.prototype = Array.prototype;
console.dir(MyArray.prototype.constructor);
MyArray.prototype.constructor = MyArray
var arr = new MyArray()
console.log("arr:",arr);
arr.push(1,2,3)
console.log("arr:",arr);
console.dir(arr.constructor);
console.log("arr.__proto__ === MyArray.prototyep:",arr.__proto__ === MyArray.prototype);
複製程式碼

控制檯列印:

image-20200315163120949
image-20200315163120949

11.總結

    // 建構函式:Foo
// 例項物件:f1
// 原型物件:Foo.prototype
function Foo() {}
var f1 = new Foo()
// 1.原型物件和例項物件的關係
console.log(Foo.prototype === f1.__proto__); // true
// 2.原型物件和建構函式的關係
console.log(Foo.prototype.constructor === Foo); // true
// 3.例項物件和建構函式
// 間接關係是例項物件可以繼承原型物件的constructor屬性
console.log(f1.constructor === Foo); // true
// 注意:程式碼順序很重要
Foo.prototype = {}
console.log(Foo.prototype === f1.__proto__); // false
console.log(Foo.prototype.constructor === Foo); // false
複製程式碼

參考資料

[1]更多文件: https://developer.mozilla.org/zh-CN/

相關文章