__proto__
, prototype
, constructor
的愛恨情仇__proto__
__proto__
屬性是對象所獨有的__proto__
所指向原型對象(父對象)裏找,一直找,直到找到萬物之源 Object 的__proto__
屬性,此時 Object 的__proto__
指向的是 null,此時就表示已經到盡頭了,確實沒有該屬性。因此__proto__
屬性的終點是 null__proto__
一層層將它們所指向的對象鏈接起來的這條鏈路就是咱們常說的原型鏈prototype
prototype
屬性是函數所獨有的,任何函數在建立的時候,會默認建立該函數的prototype
對象constructor
constructor
是對象所獨有的constructor
,由於建立對象的前提是須要有constructor
,它多是自己擁有或繼承而來。單從constructor
這個屬性來說,只有prototype
對象纔有。constructor
易被更改,因此相對沒那麼可靠Function
這個對象(也是函數)比較特殊,它的構造函數就是它本身。全部函數和對象最終都是由Function
構造函數得來,因此constructor
屬性的終點就是Function
這個函數// Demo
function Fun() {};
let fn = new Fun();
複製代碼
fn.__proto__ === Fun.prototype
fn.constructor === Fun
fn.__proto__.constructor === Fun
Fun.prototype.constructor === Fun
Fun.constructor === Function
Function.constructor === Function
Function.__proto__ === Function.prototype
Fun.prototype.__proto__ === Object.prototype
Function.prototype.__proto__ === Object.prototype
Object.prototype.__proto__ === null
Object.constructor === Function
__proto__
和constructor
屬性是對象所獨有的
prototype
屬性是函數所獨有的,但因爲 JS 中函數也是一種對象,因此函數也擁有__proto__
和constructor
屬性app
__proto__
屬性圖解prototype
屬性圖解constructor
屬性圖解constructor
結合__proto__
圖解new
試試首先,咱們須要知道new
作了哪些工做:函數
__proto__
屬性指向構造函數的原型對象prototype
// 寫法1(推薦)
// 若是第一個參數不是函數,則拋出異常,由於默認只有函數纔有prototype對象
// 用 Object.create()來建立帶有你想要的[[Prototype]]的新對象。
// 執行構造函數,而且傳遞參數,將this指向obj
// 若是構造函數自己有返回值,且這個返回值是對象類型,則return這個返回值;不然返回新對象obj
function _new(Ctor, ...arg) {
if(typeof Ctor !== 'function') {
throw `the first param must be a function`
}
let obj = Object.create(Ctor.prototype);
let ret = Ctor.apply(obj, arg);
return ret instanceof Object ? ret : obj;
}
// 定義構造函數
function Person(name = 'sakura') {
this.name = name;
console.log(this.name);
}
let person1 = _new(Person, 'eril'); // eril
let person2 = new Person('eril'); // eril
複製代碼
// 其它寫法
function _new2() {
let obj = Object.create(null); //建立一個純的空對象
let Constructor = [].shift.call(arguments); //將參數列表中的第一個參數截取出來做爲構造函數,執行完後參數列表長度-1
Object.setPrototypeOf(obj, Constructor.prototype); // 更值得推薦的設置對象原型的方法,執行完後,繼承關係成立
let rt = Constructor.apply(obj, arguments); //執行構造函數,並將this指向obj
return typeof rt === 'object' ? rt : obj; //判斷構造函數返回值是否爲對象,是則返回構造函數返回值,不然返回新建立的對象obj
}
function _new3(func) {
var res = {};
if (func.prototype !== null) {
res.__proto__ = func.prototype; //已通過時而且不推薦的修改原型對象的方法
}
var ret = func.apply(res, Array.prototype.slice.call(arguments, 1)); //先截取掉第一個參數(構造函數)
// 根據規範,返回 null 和 undefined,依然返回obj
if ((typeof ret === "object" || typeof ret === "function") && ret !== null) {
return ret;
}
return res;
}
複製代碼