這是我參與8月更文挑戰的第3天,活動詳情查看:8月更文挑戰數組
原型是一個對象markdown
如圖所示,咱們來 new 兩個 Foo 的實例來看看:app
functionFoo(){
}
let f1 = new Foo()
let f2 = new Foo()
複製代碼
每一個函數都有一個
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
__proto__
每一個對象都有
__proto__
屬性,指向了建立該對象的構造函數的原型。
console.log(f1.__proto__ === Foo.prototype); // true
複製代碼
那原型也是對象,構造函數也是對象,它們的 __proto__
屬性又指向哪裏?答案依然仍是指向了建立該對象的構造函數的原型。
__proto__
函數也是一個對象,函數的構造函數是 Function ,所以
__proto__
指向了Function.prototype
。
這是每一個對象都有的隱式原型屬性,指向了建立該對象的構造函數的原型。其實這個屬性指向了 [[prototype]]
,可是 [[prototype]]
是內部屬性,咱們並不能訪問到,因此使用 __proto__
來訪問。
由於在 JS 中是沒有類的概念的,爲了實現相似繼承的方式,經過 __proto__
將對象和原型聯繫起來組成原型鏈,得以讓對象能夠訪問到不屬於本身的屬性。
當咱們使用 new 操做符時,生成的實例對象擁有了 __proto__
屬性。
function Foo(){}
// 這個函數是 Function 的實例對象
// function 就是一個語法糖
// 內部調用了 new Function(...)
複製代碼
因此能夠說,在 new 的過程當中,新對象被添加了 __proto__
而且連接到構造函數的原型上。
new 的過程:
在調用 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()
複製代碼
__proto__
原型也是個對象,原型的構造函數是 Object,所以
__proto__
指向了Object.prototype
,而Object.prototype
這個原型對象最終指向 null。
function Person() {
}
var person = new Person();
console.log(person.constructor === Person); // true
複製代碼
console.log(Person.prototype.constructor === Person); // true
複製代碼