构造函数
constructor
返回创建实例对象时构造函数的引用。 此属性的值时对函数本身的引用,而不是一个包含函数名称的字符串。
function Parent(){
this.age = age
}
var p = new Parent(50)
p.constructor === Parent // true
p.constructor === Object // false
构造函数本身就是一个函数,与普通函数没有任何区别,不过为了规范一般将其首字母大写。构造函数和普通函数的区别在于,使用 new 生成实例的函数就是构造函数,直接调用的就是普通函数。
symbol是构造函数吗
Symbol
是基本数据类型,但作为构造函数来说它并不完整,因为它不支持语法 new Symbol()
, Chrome认为其不是构造函数,如果要生成实例直接使用 Symbol()
即可。
new Symbol(123); // Symbol is not a constructor
Symbol(123); // Symbol(123)
虽然是基本数据类型,但 Symbol(123)
实例可以获取 constructor
属性值。
var sym = Symbol(123);
console.log( sym );
// Symbol(123)
console.log( sym.constructor );
// ƒ Symbol() { [native code] }
这里的 constructor
属性其实是 Symbol
原型上的,即 Symbol.prototype.constructor
返回创建实例原型的函数,默认为Symbol
函数。
手写一个new
function create() {
// 创建一个空对象
var obj = new Object()
// 获得构造函数,arguments中取得第一个参数
Con = [].shift.call(arguments)
// 链接到原型,obj可以访问到构造函数原型中的属性
obj.__proto__ = Con.prototype
// 绑定this实现继承,obj可以访问到构造函数中的属性
var ret = Con.apply(obj, arguments)
// 优先返回构造函数返回的对象
return ret instanceof Object ? ret : obj
}
原型 prototype
每个对象拥有一个原型对象,对象以其原型为模板,从原型继承方法和属性,这些属性和方法定义在对象的构造器函数的prototype属性上,而非对象实例本身。
原型链
每个对象拥有一个原型对象,通过__proto__ 指针指向上一个原型,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向null
。 这种关系被称为原型链,通过原型链一个对象会拥有定义在其他对象的属性和方法。
我们看下面一个例子。
function Parent(age) {
this.age = age;
}
var p = new Parent(50);
p.constructor === Parent; // true
这里 p.constructor
指向 Parent
,那是不是意味着 p
实例存在 constructor
属性呢?并不是。
我们打印一下P的值。
由图可以看出,实例对象p
本身没有constructor
属性,是通过原型链向上查找__proto__,最终查到constructor
属性,该属性指向构造函数 Parent
。
function Parent(age) {
this.age = age;
}
var p = new Parent(50);
p; // Parent {age: 50}
p.__proto__ === Parent.prototype; // true
p.__proto__.__proto__ === Object.prototype; // true
p.__proto__.__proto__.__proto__ === null; // true
下图是原型链的运作机制。
小结
Symbol
作为构造函数来说并不完整,因为不支持语法new Symbol()
, 但其原型上拥有constructor
属性,即Symbol.prototype.constructor
。- 引用类型
constructor
属性值是可以修改的,但是对于基本类型来说是只读的,当然null
和undefined
没有constructor
属性。 __proto__
是每个实例上都有的属性, prototype是构造函数的属性,在实例上并不存在,所以这两个并不一样。但是p.__prototype
和Parent.prototype
指向同一个对象。__proto__
属性在 es6 时被标准化,但因为性能问题并不推荐使用,推荐使用Object.getPrototypeOf()
。- 每个对象拥有一个原型对象,通过
__proto__
指针指向上一个原型,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层,最终指向null
,这就是原型链。