现在我先不解释prototype,先看代码
先定义一个构造函数
function Fn(name) {
this.name = name;
this.say = function () {
console.log('hi');
};
}
var f1= new Fn('Tom');
var f2 = new Fn('Jack');
在watch上添加f1和f2会发现 他们name的值都是不同的
在这里我用this给它添加了,凡是声明对象就会有一个单独的name副本
单独占两个内存
f1的name和f2的name不相干
他们都有共同的函数say
如果说这个say方法占4个字节,name占4个
假定所有成员占4个字节 创建一个对象占8个
10个对象就是80个
但是方法是共享的就是方法逻辑是共享的
如果让方法不是独立存在的,那所有的对象都共享一个方法的话
一个方法占4个字节 一个name占4个字节
如果是两个对象是12个字节,因为方法时共享的 对象1+对象2+方法
如果是10个对象就是44个字节 内存就节省下了
在这种情况写,我们在创建对象的时候,一旦方法功能是相同的就让它共享
那么问题来了: 怎么共享呢?
重点:
在函数里面有一个属性叫prototype
注意!只要是个函数就有这个属性
由该函数创建的对象会默认的连接到该属性上
function F() {
}
F.prototype.num = 123;//它的prototype就是一个对象,这个prototype可以给他添加成员,在后面加点就行了
var f = new F();
console.log(f.num);
在f里面什么也没有 但是他里面有个属性proto
里面有个num,当前对象,只要被这个函数创建的对象就会默认的连接到这个prototype属性上
在prototype里面有了任何成员,那么当前对象(f)在访问的时候就会默认的访问到它(num)
举例:console.log(f.num);如果不写var f = new F();undefind
意味着当前对象中找不到这个属性
那么为什么会出现这种情况呢?
在访问对象的某一个属性(也包括方法)的时候,首先会在当前对象中查找有没有该属性
例如这里的f是一个对象,f可以通过f.age的方法给它加成员 f.age =12;name 那么这个age就是f当前对象的成员
但是如果用F创建出来的这个对象就没有这个成员
如果当前对象没有,就会在构造方法的定义规则中查找(当前对象),
如果还没有就回到与对象联系起来的构造函数的Prototype属性中找
现在我对代码稍加改动f.num =1;
function F() {
}
F.prototype.num = 123;
var f = new F();//当前函数用new创建出来的对象,一定是用new,那么默认的会链接到该属性上,这个叫继承,这里不讲继承
f.num = 1;
console.log(f.num);//打印出来1
(我这里就不贴图了)
为什么会打印出来1呢
因为先找的就是自己的,已经找到了就不会再继续找了
prototype的作用
这个就是复用数据的理想方法,把所有重复性的数据放在prototype中,
在创建对象的时候共享这个数据,在访问的时候如果我没有,就直接到prototype中找
function Fn1(name) {
this.name = name;
this.say = function() {
console.log('123');
};
}
var p1 = new Fn1('jim');
var p2 = new Fn1('tom');
//比较两个函数是否相同
console.log(p1.say === p2.say);//注意:我这里没有打(),打了是调用,判断他们的返回值,而我的函数没有返回值
//false
p1和p2对象都有一个name属性,这是无法共享的但是他们都有一个规则
对象会到与它联系的prototype中找数据
可以考虑将共享的数据,放到里面
放到里面之后,这需要在程序里面有着一个副本就可以了
如果放在构造函数里面那么创建一个对象就有一个副本,多少个对象,多少个副本
会消耗我们的内存,而且在DOM操作中有很多方法JQ也是,如果每个对象都占用这些方法,那么系统性能就完全she了
不管是哪个对象都找那一个prototype
function Fn2(name) {
this.name = name;
}
Fn2.prototype.say = function(){
console.log('hi');
};
var test1 = new Fn2('jack');
var test2 = new Fn2('Rose');
console.log(test1.say === test2.say);//true 证明这两个方法其实是同一个方法
//当前对象无论创建多少个,这个say只有一个副本
//这就是prototype的作用
对象中有一个属性叫proto
通过调试可以发现对象的proto与创建它的构造函数prototype是一个东西
举例
function Fn3(){}
var f3 = new Fn3();
console.log(f3.__proto__ === Fn3.prototype);//ture
proto是非标准属性 i8不支持
原型
Fn3.prototype =>原型属性 构造函数提供的属性
f3.proto=>原型对象
注意
构造函数的原型属性就是对象的原型对象
Fn3.prototype 是构造函数Fn3的原型属性
Fn3.prototype 是对象f3的原型对象
对前面那段话进行总结,,在访问一个对象的属性的时候,首先在当前对象中找,如果没有在其原型对象中找(就是创造它的构造函数)
var fn1 = function () {};
var fn2 = function () {};
var f1 = new fn1();
那么fn2.prototype是f1的原型对象么
这个是错的 正确的是fn1.prototype是f1的原型对象
注意:
一个对象的原型对象只和创造它的构造函数有关
构造函数的原型属性就是对象的原型对象
先有构造函数才能创建对象,有构造函数才有原型对象,所以先有原型对象才有对象,原型对象才是对象的上一级,对象里没有才到原型对象去找