会js与jq的后端开发如何愉快的转前端:第二篇-第二节:es6-面向对象-把oop玩出花-原型prototype
构造函数的原型
构造函数弊端
构造函数的原型prototype
原型和原型的作用
构造函数的弊端
浪费内存
构造函数的弊端:存在浪费内存的问题。
原型:每一个构造函数都有一个 prototype 属性,指向另一个对象。这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
原型的作用:资源共享。
为什么说 浪费内存?
写一个构造函数 用来创建学生对象
属性:姓名 年龄 身高 体重
行为:学习 吃饭 看片 把妹
function Student (name){
this . name = name ;
this . study = function (){
console . log ( "好好学习 天天向上" ) ;
}
}
如果构造函数没有参数,那么在调用的时候小括号可以省略
var stu = new Student ( "胡一天" ) ;
stu. study () ;
var stu1 = new Student ( "沈悦" ) ;
stu1. study () ;
上面两个对象的实际情况如下图:
每个学生对象的study函数都是同一句代码,那同样的代码在内存里面占两份就不合适。
那么传统的解决方法是让所有的对象共用一个方法,在构造函数外部定义好该函数,将该函数赋值给构造函数内的方法。
使用这种方式存在的问题:
1就是全局变量增多造成污染,
2就是代码结构混乱,不易维护
构造函数的原型prototype (解决弊端)
原型定义
原型:每一个构造函数都有一个 prototype 属性,指向另一个对象。这个 prototype 就是一个对象,这个对象的所有属性和方法,都会被构造函数所拥有。
作用:资源共享
一般情况下,我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上
代码:
<body>
<script>
// 1. 构造函数的问题.
function Star(uname, age) {
this.uname = uname;
this.age = age;
// this.sing = function() {
// console.log('我会唱歌');
// }
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var dmm = new Star('大幂幂', 18);
var bo = new Star('波波', 19);
console.log(dmm.sing === bo.sing); // 如果不是公共方法,这里就是false
// console.dir(Star);
dmm.sing();
bo.sing();
// 2. 一般情况下,我们的公共属性定义到构造函数里面, 公共的方法我们放到原型对象身上
</script>
</body>
对象原型的方法
proto 我自己的对象原型
对象身上系统自己添加一个__proto__
指向我们构造函数的原型对象 prototype
<body>
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var dmm = new Star('大幂幂', 18);
var bo = new Star('波波', 19);
dmm.sing();
console.log(dmm); // 对象身上系统自己添加一个 __proto__ 指向我们构造函数的原型对象 prototype
console.log(dmm.__proto__ === Star.prototype);
// 方法的查找规则: 首先先看dmm 对象身上是否有 sing 方法,如果有就执行这个对象上的sing
// 如果没有sing 这个方法,因为有__proto__ 的存在,就去构造函数原型对象prototype身上去查找sing这个方法
</script>
</body>
属性 constructor 指回 原来的构造函数
很多情况下,我们需要手动的利用 constructor
这个属性指回 原来的构造函数
为什么要指回去?
运用场景 :编写两个对象原型方法.
思考: 我能不能简单点优化代码?
Star.prototype.sing = function() {
console.log('我会唱歌');
};
Star.prototype.movie = function() {
console.log('我会演电影');
}
开始优化,合并 prototype,修改原型
<body>
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
// 2. 直接定义一个新的prototype
// constructor 这个属性指回 原来的构造函数
Star.prototype = {
// 如果我们修改了原来的原型对象,给原型对象赋值的是一个对象,则必须手动的利用constructor指回原来的构造函数
// 如果不指回去,此行注释,则无法找到原来的构造函数
// 打印Star.prototype.constructor dmm.__proto__.constructor 只有此构造函数中的 sing 与 movie
// 很多情况下,我们需要手动的利用constructor 这个属性指回 原来的构造函数
constructor: Star,
sing: function() {
console.log('一生一世');
},
movie: function() {
console.log('php啊');
}
}
var dmm = new Star('大幂幂', 18);
var bo = new Star('波波', 19);
console.log(Star.prototype);
console.log(dmm.__proto__);
console.log(Star.prototype.constructor);
console.log(dmm.__proto__.constructor);
</script>
</body>
如果不指向 原型,则打印如图:(直接把指向注释掉)
指向原型:
原型链
- 只要是对象就有
__proto__
原型, 指向原型对象 - 我们
Star
原型对象里面的__proto__
原型指向的是Object.prototype
- 我们
Object.prototype
原型对象里面的__proto__
原型 指向为null
<body>
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
Star.prototype.sing = function() {
console.log('我会唱歌');
}
var dmm = new Star('大幂幂', 18);
// 1. 只要是对象就有__proto__ 原型, 指向原型对象
console.log(Star.prototype);
console.log(Star.prototype.__proto__ === Object.prototype);
// 2.我们Star原型对象里面的__proto__原型指向的是 Object.prototype
console.log(Object.prototype.__proto__);
// 3. 我们Object.prototype原型对象里面的__proto__原型 指向为 null
</script>
</body>
原型对象中this指向
在构造函数中,里面this指向的是对象实例
原型对象函数里面的this 指向的是 实例对象
<body>
<script>
function Star(uname, age) {
this.uname = uname;
this.age = age;
}
var that;
Star.prototype.sing = function() {
console.log('我会唱歌');
that = this; // 指向的是 实例对象 dmm
}
var dmm = new Star('大幂幂', 18);
// 1. 在构造函数中,里面this指向的是对象实例 dmm
dmm.sing();
console.log(that === dmm);
// 2.原型对象函数里面的this 指向的是 实例对象 dmm
</script>
</body>
结果:
true
原型对象的应用 扩展内置对象方法
可以通过原型对象,对原来的内置对象进行扩展自定义的方法。比如给数组增加自定义求偶数和的功能。
注意: 数组和字符串内置对象不能给原型对象覆盖操作Array.prototype ={}
,只能是Array.prototype.xx = function
追加 的方式。
<body>
<script>
// 原型对象的应用 扩展内置对象方法
Array.prototype.sum = function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
};
// 这一段会直接报错,js本身存在sum 这个方法咱们还是要的,不可能覆盖。
// 我们只可以通告追加的形式来扩展内置对象方法
// Array.prototype = {
// sum: function() {
// var sum = 0;
// for (var i = 0; i < this.length; i++) {
// sum += this[i];
// }
// return sum;
// }
// }
var arr = [1, 2, 3];
console.log(arr.sum());
console.log(Array.prototype);
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());
</script>
</body>
执行截图:
如果使用覆盖形式进行运行(把上面代码 注释的地方打开,追加形式扩展的sum 注释):
<body>
<script>
// 原型对象的应用 扩展内置对象方法
// Array.prototype.sum = function() {
// var sum = 0;
// for (var i = 0; i < this.length; i++) {
// sum += this[i];
// }
// return sum;
// };
Array.prototype = {
sum: function() {
var sum = 0;
for (var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
}
var arr = [1, 2, 3];
console.log(arr.sum());
console.log(Array.prototype);
var arr1 = new Array(11, 22, 33);
console.log(arr1.sum());
</script>
</body>
执行结果:
数组和字符串内置对象不能给原型对象覆盖操作Array.prototype ={}
,只能是Array.prototype.xx = function
追加 的方式。
本作品采用《CC 协议》,转载必须注明作者和本文链接
催更