JavaScript进阶笔记(五):构造函数、原型和原型链
摘要:// 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