AKA__proto__
, prototype
, constructor
的爱恨情仇
__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
属性
图解
__proto__
属性图解
prototype
属性图解
constructor
属性图解
constructor
结合__proto__
图解
总结图解
手写一个new
试试
首先,我们需要知道new
做了哪些工作:
- 创建一个新的对象obj
- obj对象的
__proto__
属性指向构造函数的原型对象prototype
- 执行构造函数,并且传递参数,改变this的指向,指向新生成的对象obj
- 如果构造函数本身有返回值,且这个返回值是对象类型,则return这个返回值;否则返回新对象obj(根据规范,返回 null 和 undefined,依然返回obj)
// 写法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;
}
复制代码