构造函数
所谓构造函数,其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。构造函数始终应该以一个大写字母开头,非构造函数应该以一个小写字母开头
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
原型
让某一大类都具有共同的方法
Person.prototype.sayName = function(){
alert(this.name);
};
对象实例进阶
指针的概念:当我们定一个变量的时候,会在内存中开辟一段区域保存这个变量的值,每个内存区域都有一个对应的地址,我们一般都是通过地址找到这个值的。类似门牌号 。
对象时如何在内存中存储的:在内存中开辟两段区域,一段区域存储变量名称(地址),一段区域才是存储实例真正的值。
var product = new product();
product变量中保存的只是地址,具体的内容放在另一块区域里面。
对象拷贝理论
- 实例化的过程其实就是拷贝构造函数所有属性(包含定义的也包含隐藏的)的过程
- 除了拷贝以外还会自动生成一个constructor属性,用于识别其是根据哪个构造函数创建的实例。
- 每当我们实例化的时候,都会将构造函数的属性拷贝一份,同时赋给新值,就给将内存空间替换掉。
- constructor:构造函数隐藏的一个属性。
原型的属性(方法)共享理论
原型对象不管实例化多少次,都只会生成一次。
- 只用构造函数创建对象存在的缺点
- 对象需要实例化
- 每次实例化都要分配内存存储这些数据
- 如果实例很多,那就要分配很多内存存储
- 一般每个实例的属性是不一样的,而行为一般都是一样的,所以我们希望实例化的时候,只分配内存保存不一样的数据。
- 而像方法,可以只分配一次空间,所有的实例共享这些方法,那就需要原型对象。
- 原型对象只分配一次内存
- 实例化的时候只拷贝构造函数中的属性,而不会拷贝原型对象中的属性。
- 原型对象的本质:
- 原型对象的属性和方法可以被所有实例共享
- 这样,如果我们修改所有实例中的属性或者方法,就只需要修改移除,就能够影响所有实例了。
函数搜索机制
本质:通过prototype属性中保存的地址链接原型
-
先在自己的属性列表中寻找,如果找到直接返回,如果找不到从原型中寻找。如果找不到,先找到自身的一个隐藏属性prototype,这个属性中保存的是原型对象的地址。
-
任何一个我们编写的函数其实都是Function对象,既然对象是函数实现的,那么对象也是Function的一个实例,所以构造函数含有Function对象中的一切属性和方法。而constructor属性,prototype属性是Function对象中的属性之一,而实例化的时候会拷贝构造函数中的属性和方法,自然就有了constructor属性和prototype属性。
-
prototype属性--保存的就是地址。
-
作用:将实例和原型对象联系在一起。
双对象法则
- 构造函数对象
- 原型对象
- 通过属性-proto-联系在一起
- 实例化的时候,实例首先拷贝构造函数的所有属性,先在自己的属性列表中寻找,如果找不到,先找到自身的一个隐藏属性prototype,这个属性中保存的是原型对象的地址。
prototype、proto和constructor的三角关系
function Foo(name, age, job){
this.name = name;
this.age = age;
this.job = job;
};
Foo.prototype.sayName = function(){
alert(this.name);
};
var f1 = new Foo;
//__proto__属性指向实例的原型对象
console.log(f1.__proto__ === Foo.prototype)//true
//constructor属性指向创建它的构造函数
console.log(f1.constructor === Foo);//true
console.log(Foo.prototype.constructor === Foo);//true