javaScript:3天理解面向对象(2)

作者: 小飞蚁 | 来源:发表于2017-09-21 08:54 被阅读0次

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的实例。

对象的本质

无续的键值对的组合;

相关文章

网友评论

    本文标题:javaScript:3天理解面向对象(2)

    本文链接:https://www.haomeiwen.com/subject/liqasxtx.html