javaScript:3天理解面向对象(2)
prototype
理解:每个构造函数都有prototype原型属性,这个属性是对象类型,这个属性里面有两个属性constructor和proto;原型属性的constructor指向构造函数;(原型对象上面的属性proto我们今天先不考虑)实例对象的proto指向构造函数的原型;
根据案例来讲解:
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.showName=function(){
console.log(this.name+"helloWord!");
}
var p1=new Person("小白",18);
var p2=new Person("小黄",18);
这是一个标准的构造函数,接下来我们来分析一下,prototype这个属性;
1.每个构造函数都有prototype这个原型属性;
证明:console.dir(Person);
从这张图片可以看出,每个构造函数都有一个prototype属性(红色的方框标记的),这个属性是对象类型(因为prototype的值是键值对,键值对是对象的标志)这个对象里面有两个属性一个是constructor(绿色的边框标记的)一个是proto(黑色边框标记的);
2.constructor属性指向构造函数;
证明:console.log(Person.prototype.constructor===Person);
输出的结果为:true;这就证明了,prototype的constructor属性指向,构造函数;
3.proto,实例对象里面也有一个proto属性,这个属性指向构造函数的原型;
证明:console.log(p1.proto===Person.prototype);
输出的结果为:true;这就说明了,实例对象的属性proto,指向构造函数的原型;
我们从内存图的角度来说明这个Person这个对象;
好好的理解一下这个内存图;
Tab栏案例;
用面向对象的方式编程;
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<style type="text/css">
#tab div{
width: 200px;
height: 200px;
background: red;
font-size: 30px;
display: none;
}
</style>
</head>
<body>
<div id="tab">
<input type="button" value="苹果"/>
<input type="button" value="橘子"/>
<input type="button" value="香蕉"/>
<div>苹果</div>
<div>橘子</div>
<div>香蕉</div>
</div>
<script>
function Tab (id) {
this.odiv=document.getElementById("tab");
this.adiv=this.odiv.getElementsByTagName('div');
this.ainput=this.odiv.getElementsByTagName('input');
}
Tab.prototype.innit=function () {
this.adiv[0].style.display='block';
this.ainput[0].style.backgroundColor='orange';
for (var i=0;i<this.ainput.length;i++) {
this.ainput[i].index=i;
var _this=this;
this.ainput[i].onclick=function () {
_this.change(this);
}
}
this.autoplay();
}
Tab.prototype.change=function (obj) {
for (var j=0;j<this.adiv.length;j++) {
this.ainput[j].style.backgroundColor='';
this.adiv[j].style.display='none';
}
obj.style.backgroundColor='orange';
this.adiv[obj.index].style.display='block';
}
Tab.prototype.autoplay=function () {
this.nowIdex=0;
var that=this;
setInterval(function () {
if(that.nowIdex===that.adiv.length-1){
that.nowIdex=0;
}else{
that.nowIdex++;
}
that.change(that.ainput[that.nowIdex]);
},1000);
}
var tab=new Tab('tab');
tab.innit();
</script>
</body>
</html>
初识原型链
原型链是什么?
原型链是有实例对象的属性和方法组成,通过protot链接到一起;
function Person(name,age){
this.name=name;
this.age=age;
}
Person.prototype.showAge=function(){
console.log(this.name+'hello word !');
}
var p=new Person("zhangsan",18);
从以上的知识可以知道:
1).每个构造函数都有一个prototype属性,这个属性是一个对象,这个属性里面有两个属性一个是constructor另一个是proto;
2).原型中的constructor指向构造函数;
3).实例对象中的proto指向构造函数的原型;
证明:
console.log(Person.prototype.constructor===Person);//true;
console.log(P.proto===Person.prototype);//true;
既然构造函数的原型有两个属性,一个是constructot(指向构造函数),一个是proto,那么proto指向哪里?
我们先来打印一下,console.dir(Person.prototype.proto);
然后我们在来打印一下,console.dir(Object.prototype);
从图中可以知道,Person.prototype.proto===Object.prototype;
console.log(Person.prototype.proto===Object.prototype);//true;
从这里可以知道,prototype下面的constructor指向构造函数,prototype中的proto
指向,Object.prototype;
所以,就产生了一条链式结构;
p->Person.prototype->Object.prototype->null;
var arr=[];
arr->arr.prototype->Object.prototype->null;
var obj={};
obj->Object.prototype->null;
为什么Object.prototype.proto指向空呢??
大家看一下,Object.prototype上面没有proto属性,所以指向null;
证明:
console.dir(p.proto.proto.proto);
那么了解这写有什么用呢??
function Animal(name){
this.name=name;
}
Animal.prototype.showAge=function(){
console.log(this.name+'hello word');
}
function Dog(color){
this.color=color;
}
Dog.prototype=new Animal('小白');
var dog=new Dog('黄色');
console.log(dog.color);
console.log(dog.name);
dog.showAge();
为什么构造函数Animal上面的方法,构造函数Dog可以访问的到,我们画一张图来表示一下;
那我们把下面的代码在更改一下:
function Animal(name){
this.name=name;
}
Animal.prototype.showAge=function(){
console.log(this.name+'hello word');
}
function Dog(color){
this.color=color;
}
Dog.prototype=new Animal('小白');
Dog.prototype.showAge=function(){
console.log(this.name+':hellow word');
}
var dog=new Dog('黄色');
我在Dog的prototype上面加了一个方法,那么dog的实例能不能访问的到?
dog.showAge();
我们看一下内存图的变化;
![]
dog.showAge()是可以访问到的,因为Dog.prototype被指向为new Animal(),所以dog的showAge方法加在了new Animal()上面,new dog的实例通过proto可以访问到new Animal()上面。但是这样的话,我们就会发现,Dog.prototype.construcot===Animal;这样是不符合我们规定的;
那要是这样改动,内存图会有什么变化;
function Animal(name){
this.name=name;
}
Animal.prototype.showAge=function(){
console.log(this.name+'hello word');
}
function Dog(color){
this.color=color;
}
Dog.prototype=new Animal('小白');
Dog.prototype.showAge=function(){
console.log(this.name+':hellow word');
}
Dog.prototype.constructor=Dog;
var dog=new Dog('黄色');
;
代码我们在改动一下:
function Animal(name){
this.name=name;
}
Animal.prototype.showAge=function(){
console.log(this.name+'hello word');
}
function Dog(color){
this.color=color;
}
Dog.prototype=new Animal('小白');
Dog.prototype.showAge=function(){
console.log(this.name+':hellow word');
}
Dog.prototype.constructor=Dog;
Object.prototype.showFn=function () {
console.log(this.name+':1122222222');
};
var dog=new Dog('黄色');
Dog.prototype.constructor=Dog;
内存图发生了什么变化?
;
我们在来看一下这个案例,内存图的变化;
function Animal (name,age) {
this.name=name;
this.age=age;
}
Animal.prototype={
constructor:Animal,
showAge:function () {
console.log(this.name+'hello Word');
},
showName: function (){
console.log(this.name+"我今年"+this.age+"岁了");
}
};
var animal=new Animal('小白',19);
animal.showAge();
animal.showName();
继承;
继承分为原型继承和构造函数继承;
原型继承;
function Person (name) {
this.name=name;
this.score=[20,30,40,50];
}
function Student (age) {
this.age=age;
}
Person.prototype.showName=function(){
console.log(this.name+':下班回家很晚');
}
Student.prototype=new Person('tom');
Student.prototype.showAge=function () {
console.log(this.name+":下班回来晚了");
}
var stu=new Student(29);
var stu1=new Student(35);
stu.score.push(100);
console.log(stu.score);
console.log(stu1.score);
stu.showAge();
stu1.showAge();
console.log(stu.name);
console.log(stu1.name);
原型继承的缺点:
1.原型继承中的要传的参数已经无法更改(我想让stu1获取name的属性为tom,stu2获取name的属性为Jerry,但是这样无法做到);
2.所继承的函数中的引用类型的数据被所有的实例,所共享;
借用构造函数继承;
function Person (name) {
this.name=name;
this.score=[20,30,40,50];
}
Person.prototype.showAge=function () {
console.log(this.name+':我已经完成le');
}
function Student (name,age) {
Person.call(this,name);
this.age=age;
}
var stu=new Student("Jerry",29);
stu.score.push(100);
console.log(stu.score);
var stu1=new Student("Tom",35);
console.log(stu1.score);
console.log(stu.name);
console.log(stu.age);
console.log(stu1.name);
console.log(stu1.age);
stu.showAge();
stu1.showAge();
借用构造函数继承的缺点:
1.无法继承构造函数原型上面的方法;
最佳的继承方法:组合继承;
function Person (name) {
this.name=name;
this.score=[20,30,40,50];
}
Person.prototype.showAge=function () {
console.log(this.name+':我已经完成le');
}
function Student (name,age) {
Person.call(this,name);
this.age=age;
}
Student.prototype=new Person();
var stu=new Student("Jerry",29);
stu.score.push(100);
var stu1=new Student("Tom",35);
对象全家福
1.每个函数都有一个prototype和proto;
2.如果这个函数是构造函数,那么主要用这个Prototype这个属性,这个属性是个对象,
默认有两个属性一个是constructor和proto;constructor指向这个构造函数,proto指向Object.prototype;
3.实力对象中的proto指向构造函数的原型;
4.如果这个函数是普通函数,那么proto指向Function.prototype,Function的 proto指向Object.prototype;
5.Function中的proto指向Function.prototype,也就是说,Function是Function的实例;
6.所有的函数都是Function的实例。
对象的本质
无续的键值对的组合;