知识点整理于你不知道的js上卷
构造函数最准确的解释是:所有带new的函数调用。
并非函数本身就是一个构造函数,而是当你在普通函数调用前面加上new关键字,就会把这个函数调用编程一个构造函数调用。实际上,new会劫持所有普通函数并用构造函数的形式来调用它。
每个对象在创建时都会自动拥有一个constructor属性默认指向构造函数。实际上这个对象本身没有constructor属性,是往上原型链找到构造函数的prototype里找到了其constructor最终会指向构造函数本身。
//Person函数在声明时不仅产生了一个对象Person.prototype,而且这个对象默认存在一个属性时constructor指向这个Person函数本身
Person.prototype.constructor==Person;//true
如果你创建了一个新对象并替换了函数默认的.prototype对象引用,那么新对象并不会自动获得.constructor属性。但是这个Foo原型也没有.constructor属性,所以它会继续委托,这次会委托给委托链顶端的Object.prototype,这个对象有.condtructor属性,指向内置的Object函数。
由于函数默认的constructor并不是一个不可变属性,它是不可枚举但值是可修改的,你还可以给任意[[prototype]]链中的任意对象添加一个名为constructor的属性或者对其进行修改,你可以任意对其赋值。所以这样非常不可靠也不安全,如果默认的constructor属性一旦被修改,那么它所有实例如果有用到该属性,都会发生出乎意料的结果。
function Foo(){...};
Foo.prototype = {...};//创建一个新原型对象
//给新原型对象添加constructor属性
Object.defineProperty(Foo.prototype,"constructor",{
enumerable:false,
writable:true,
configurable:true,
value:...//修改constructor指向
});
var a1 = new Foo();
a1.construtor == Foo;//false
a1.construtor == Object;//true
使用构造函数创建对象的优缺点
优点:创建对象方便
缺点:占用空间,浪费系统资源(对于每一个实例对象render方法都是一模一样的内容,但是每生成一次实例,只要调用里面的方法,这个方法在内存中就会开辟一个新的空间,就会多用一些内存,如果有很多的实例,那么就会造成极大的内存浪费)。如果在全局情况下声明函数,虽然解决了内存资源浪费的问题,但是又会出现全局变量污染的问题。可以重新声明一个对象专门存放这些方法,但是新的问题是如果有很多个构造函数,就要声明很多个这样的对象。
console.log(p1.render === p2.render) // 此时为 false 表示不是同一个地址 。
解决:使用原型对象。对象中公共的成员可以放到原型对象中去,这样实例化出来的所有的对象都可以访问,对象中的成员的访问规则是如果对象中有,先访问自己的如果没有在从原型中找。
var Person1 = new Person('小白', 12)
Person1.sayhi = function(){
console.log('这是对象自己的方法');
}
Person.prototype.sayhi = function(){
console.log('这是添加在原型中的方法');
}