1.传统原型法:
a. 当完成一个函数声明之后, js引擎会自动的创建一个对象, 这个对象表示函数对象.函数对象会有一个属性 prototype, 他指向一个对象, 这个对象也是自动创建出来的, 这个对象
就是函数的原型对象.
原型对象也有一个属性: constructor , 表示构造器,他会指向函数对象.
b. 任何的函数都会有原型对象. 只是, 我们只关注和研究构造函数的原型对象, 普通函数的原型对象
我们不关注.
<script>
function Person(name, age){
this.name = name;
this.age = age;
//如果方法写在函数对象里,那么每次new一个对象就会调用一次方法,在堆内存中创建一个函数对象,很占内存。
/*this.speak = function (){
console.log("我是对象上的方法");
}*/
}
Person.prototype.sex = "男";
//在原型对象上写方法,会比较灵活,而且不占内存。
Person.prototype.speak = function (){
console.log("我是原型对象上的方法");
}
var p1 = new Person("李四", 20);
console.log(p1.age);
console.log(p1.name);
//对象p1没有属性sex,他会通过不可见属性[[ proto]]去访问原型对象里的sex
console.log(p1.sex);
//speak方法写在了原型里,作用是不占过多的内存
p1.speak();
//检测Person.prototype,就是检测其原型对象是谁。在这里原型对象里有speak方法和sex属性。
console.log(Person.prototype);
//判断原型的constructor的指向是不是person,实际上的确,返回true。
console.log(Person.prototype.constructor === Person);
</script>
运行结果:
2.组合模式原型法
所谓组合那就是把属性封装在一起,把所有的方法写在原型里。
a. 数据属性, 应该放在对象本身. 在构造函数中使用 this.xxx = XXX
b. 方法应该添加在原型对象上. 因为方法最好所有的对象所共有.
这种封装性比较差,相对无言。
而且这种的话,每次调用会产生垃圾,比如三次调用同一原型中的同一方法,那么就会两次覆盖其原型的属性,产生了两次的垃圾。为了防止垃圾的产生,我们就有了第三种的动态原型。先看这种组合模式原型:
<script>
// 组合模型创建对象的方式
function Person(name, age){
this.name = name;
this.age = age;
}
//将所有方法写在原型对象里
Person.proto