JavaScript 系列之原型(一)

這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰數組

1、原型

原型是一個對象markdown

image.png

如圖所示,咱們來 new 兩個 Foo 的實例來看看:app

functionFoo(){

}
let f1 = new Foo()
let f2 = new Foo()
複製代碼

1.1 prototype

每一個函數都有一個 prototype 屬性(除了 Function.prototype.bind()),該屬性指向原型。ide

function Foo(){

}

Foo.prototype.msg = 'hello';
var f1 = new Foo();
var f2 = new Foo();
console.log(f1.msg) // hello
console.log(f2.msg) // hello
複製代碼

基本上全部函數都有這個屬性,可是也有一個例外函數

let fun = Function.prototype.bind()
複製代碼

若是你以上述方法建立一個函數,那麼能夠發現這個函數是不具備 prototype 屬性的。post

當咱們聲明一個函數時,這個屬性就被自動建立了。ui

function Foo(){}
複製代碼

構造函數的 prototype 屬性指向原型對象this

原型是一個對象,每個 JavaScript 對象(null 除外)在建立的時候就會與之關聯另外一個對象,這個對象就是咱們所說的原型,每個實例對象都會從原型繼承屬性。lua

如上栗子,Foo 函數也是一個對象,該構造函數對象有一個 prototype 屬性,指向實例 f1 和 f2 的原型對象即 Foo.prototype 。而在原型對象上掛在的屬性和方法都屬於公共屬性或者公共方法,由全部該構造函數 new 的實例對象所共有,即 f1 和 f2。url

1.2 __proto__

每一個對象都有 __proto__ 屬性,指向了建立該對象的構造函數的原型。

console.log(f1.__proto__ === Foo.prototype); // true
複製代碼

那原型也是對象,構造函數也是對象,它們的 __proto__ 屬性又指向哪裏?答案依然仍是指向了建立該對象的構造函數的原型

1.2.1 構造函數的 __proto__

函數也是一個對象,函數的構造函數是 Function ,所以 __proto__ 指向了 Function.prototype

這是每一個對象都有的隱式原型屬性,指向了建立該對象的構造函數的原型。其實這個屬性指向了 [[prototype]],可是 [[prototype]] 是內部屬性,咱們並不能訪問到,因此使用 __proto__ 來訪問。

由於在 JS 中是沒有類的概念的,爲了實現相似繼承的方式,經過 __proto__ 將對象和原型聯繫起來組成原型鏈,得以讓對象能夠訪問到不屬於本身的屬性。

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

function Foo(){}
// 這個函數是 Function 的實例對象
// function 就是一個語法糖
// 內部調用了 new Function(...)
複製代碼

因此能夠說,在 new 的過程當中,新對象被添加了 __proto__ 而且連接到構造函數的原型上。

new 的過程:

  1. 新生成了一個對象
  2. 連接到原型
  3. 綁定 this
  4. 返回新對象

在調用 new 的過程當中會發生以上四件事情,咱們也能夠試着來本身實現一個 new,在這以前先來重溫一個知識點:

// this指向調用的對象,當用了call後,可以改變this的指向,也就是指向傳進來的對象,這是關鍵
// shift()函數是將數組的第一個值刪除,並返回,這裏是獲得obj
[].shift.call(arguments)

由於 arguments 構造以下,第一個是長度
{length:2,0:'first',1:'second'};
複製代碼
function create() {
  // 建立一個空的對象
  let obj = new Object();
  // 得到構造函數:將第一個參數 Person 刪除並返回
  let Con = [].shift.call(arguments);
  // 連接到原型
  obj.__proto__ = Con.prototype;
  // 綁定 this,執行構造函數
  let result = Con.apply(obj, arguments);
  // 確保 new 出來的是個對象 return
  typeof result === "object" ? result : obj;
}

function Person(name, age) {
  this.name = name;
  this.age = age;
}
var a = create(Person, "小花", "16");
console.log(a); // Person {name: "小花", age: "16"}
複製代碼

對於實例對象來講,都是經過 new 產生的,不管是 function Foo() 仍是 let a = { b : 1 }

function Foo(){}
// function 就是個語法糖
// 內部等同於 new Function()

let a = { b: 1 }
// 這個字面量內部也是使用了 new Object()
複製代碼

1.2.2 原型的 __proto__

原型也是個對象,原型的構造函數是 Object,所以 __proto__ 指向了 Object.prototype,而 Object.prototype 這個原型對象最終指向 null。

1.3 constructor

  • 實例的屬性 constructor 指向構造函數
function Person() {

}
var person = new Person();
console.log(person.constructor === Person); // true
複製代碼
  • 構造函數的原型的 constructor 會指向這個函數
console.log(Person.prototype.constructor === Person); // true
複製代碼
相關文章
相關標籤/搜索