摘要:// 2、创建一个空的对象并链接到原型,obj 可以访问构造函数原型中的属性 var obj = Object.create(Con.prototype)。// 3、链接到原型,obj 可以访问构造函数原型中的属性 Object.setPrototypeOf(obj, Con.prototype)。

constructor 返回创建实例对象时构造函数的引用。此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。

构造函数和普通函数没有区别,不同点是构造函数使用 new 来生成实例对象,直接调用就是普通函数。

注意:构造函数首字母通常大写。

1.1 Symbol 是构造函数吗?

Symbol 是基本数据类型,他不支持 new Symbol() 操作。

生成 Symbol 实例直接使用 Symbol() 即可。

虽然不是构造函数,但可以获取到 constructor 属性值。

var sym = Symbol('sym')
sym.constructor
// ƒ Symbol() { [native code] }

这个 constructor 是哪里来的?其实是 Symbol 原型上的。 Symbol.prototype.construnctor 返回创建实例原型的函数。

1.2 constructor 值是只读的吗?

分为两种情况:属性值为基本数据类型是只读。属性值为引用类型是可以修改的。

可以直接对 constructor 进行赋值。

new 的实现:

function create() {
	// 1、创建一个空的对象
    var obj = new Object(),
	// 2、获得构造函数,同时删除 arguments 中第一个参数
    Con = [].shift.call(arguments);
	// 3、链接到原型,obj 可以访问构造函数原型中的属性
    Object.setPrototypeOf(obj, Con.prototype);
	// 4、绑定 this 实现继承,obj 可以访问到构造函数中的属性
    var ret = Con.apply(obj, arguments);
	// 5、优先返回构造函数返回的对象
	return ret instanceof Object ? ret : obj;
};

二、原型

JavaScript 是一种基于原型的语言 (prototype-based language),这个和 Java 等基于类的语言不一样。

每个对象拥有一个原型对象,对象以其原型为模板,从原型继承方法和属性,这些属性和方法定义在对象的构造器函数的 prototype 属性上,而非对象实例本身。

function Person () {
    this.name = 'owenli'
    this.age = 12
}
Person.prototype.constructor === Person // true

构造函数有个指针指向原型,原型有个指针指向构造函数。

2.1 __proto__

在原型(Person.prototype)中有个 __proto__ 属性,它是访问器属性。通过它可以访问内部的 [[Prototype]][[Prototype]] 是对象的内部属性,外部代码无法直接访问。

var p = new Person()
p.__proto__ === Person.prototype // true

p.__proto__ 可以直接访问到对象的原型, __proto__ 是每个实例都有的属性。 prototype 是构造函数的属性。它们指向同一个对象。

注意: __proto__ 是 ES6 的标准,兼容性问题和性能问题,推荐使用 Object.getPrototypeOf() 。考虑性能问题,避免修改 [[prototype]]

如果创建一个新对象,同时继承另一个对象的 [[prototype]] ,推荐用 Object.create()

优化 new 的实现:

function create() {
	// 1、获得构造函数,同时删除 arguments 中第一个参数
    Con = [].shift.call(arguments);
	// 2、创建一个空的对象并链接到原型,obj 可以访问构造函数原型中的属性
    var obj = Object.create(Con.prototype);
	// 3、绑定 this 实现继承,obj 可以访问到构造函数中的属性
    var ret = Con.apply(obj, arguments);
	// 4、优先返回构造函数返回的对象
	return ret instanceof Object ? ret : obj;
};

三、原型链

每个对象拥有一个原型对象,通过 proto 指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向 null。这种关系被称为原型链 (prototype chain),通过原型链一个对象会拥有定义在其他对象中的属性和方法。

var p = new Person()
p.constructor === Person

p 实例也有 constructor ,并不是。实例本身是没有 constructor 属性的,是通过原型链向上查找 __proto__ ,最终查找到 constructor 属性,该属性指向 Person

p.constructor === Person //true
p.__proto__ === Person.prototype //true
p.__proto__.__proto__ === Object.prototype //true
p.__proto__.__proto__.__proto__ === null // true
相关文章