原型对象(上)

一、引入

1、JS是一门脚本语言,解释型语言、弱类型语言、基于对象的语言、动态型语言

2、继承(面向对象有三个特性:封装、继承、多态  )是指类与类之间的关系,JS中没有类的概念,JS中有构造函数的概念,是可以继承的,是基于原型

3、创建对象的三种方法:字面量、系统方法构造函数、自定义构造函数

   <script>
    //字面量
    var per1={
        name:"刘备",
        age:25,
        show:function(){
            console.log("双股剑");
        }
    }
    //系统方法构造函数创建对象
    var per2=new Object;
    per2.name="张飞";
    per2.age=23;
    per2.show=function(){
        console.log("丈八蛇矛");
    }
    //自定义构造函数创建对象
    function Person(name,age){
        this.name=name;
        this.age=age;
        this.show=function(){
            console.log("青龙偃月刀");
        }
    }
    var per3=new Person("关羽",24)
    </script>

4、工厂模式和自定义构造函数的区别

  • 共同点:都是函数、都可以创建对象、都可以传入参数
  • 工厂模式:函数名小写,有new,有返回值,new之后的对象是当前的对象,对象创建,直接调用函数
  • 自定义构造函数:函数名大写(首字母),没有new,没有返回值,this是当前对象,对象创建,通过new出来(实例化对象)
   <script>
    //自定义构造函数创建对象
    function Person(name,age){
        this.name=name;
        this.age=age;
        this.show=function(){
            console.log("青龙偃月刀");
        }
    }
    var per1=new Person("关羽",24);
    //工厂模式创建对象
    function creatObj(name,age){
            var obj= new Object;
            obj.name=name;
            obj.age=age;
            obj.show=function( ){
                console.log("青釭剑");
            }
            return obj;
    }
    var per2=new creatObj("赵云",29);

5、构造函数和实例函数之间的关系

  • 注意:使用console.dir可以查看结构
  • 实例对象是通过构造函数来创建的,创建的过程叫实例化
  • 实例化对象会指向自己的构造函数(暂时理解)
  • 判断对象是不是这个数据类型,可以通过构造器的方法(实例对象.构造器==构造器名字)或者instanceof(对象 instanceof 构造函数名字 ),推荐后者
   <script>
    function Person(name,age){
        this.name=name;
        this.age=age;
        this.show=function(){
            console.log("青龙偃月刀");
        }
    }
    var per=new Person("关羽",24);
    //查看结构---看下图
    console.dir(Person);//构造函数
    console.dir(per);//实例对象
    //判断对象是不是这个数据类型
    //方法一:
    console.log(per instanceof Person);//true
    //方法二:
    console.log(per.constructor==Person);//true
    </script>

6、构造函数创建对象带来的问题

  • 产生多个内存空间
    <script>
        //创建的两个实例对象的方法虽然相同,但是并不相等,如果创建的对象过多,就会使占用过多内存
        function Person(name,age){
            this.mame=name;
            this.age=age;
            this.eat=function(){
                console.log("吃饭");
            }
        }
        var per1=new Person("李白",44);
        var per2=new Person("杜甫",50);
        console.log(per1.eat==per2.eat);//false
    </script>
  • 可以通过使用命名函数方法解决,但是可能会有变量冲突
    <script>
        //通过使用命名函数方法解决,但是可能会有变量冲突-----最好引入原型
        function Person(name,age){
            this.mame=name;
            this.age=age;
            this.eat=myEat;
        }
        function myEat(){
            console.log("吃饭");
        }
        var per1=new Person("李白",44);
        var per2=new Person("杜甫",50);
        console.log(per1.eat==per2.eat);//true
    </script>
  • 所以最好引入原型来解决

二、原型对象

1、构造函数创建函数带来的问题,可以通过原型的方法解决-----原型的作用之一:可以实现数据共享,节省内存空间

2、通过原型来添加方法:构造函数.prototype.方法名=一个函数

   <script>
    function Person(name,age){
        this.mame=name;
        this.age=age;
    }
    Person.prototype.eat=function(){
            console.log("吃饭");
        }
    var per1=new Person("李白",44);
    var per2=new Person("杜甫",50);
    console.log(per1.eat==per2.eat);//true
    </script>

3、案例:点击按钮改变div样式(使用原型的方法)

4、什么是原型?

  • 实例对象中有个属性,__proto__,也是对象,叫原型,不是标准的属性,在IE8中可能不支持,主要给是给浏览器使用的
  • 构造函数中有个属性,prototype,也是对象,叫原型,是标准属性,主要给程序开发人员使用
  • 所以原型就是__proto__或者prototype,都是原型对象

5、构造函数、原型对象、实例对象之间的关系(画图)

  • 构造函数可以实例化对象,产生实例对象
  • 构造函数中有一个属性,prototype,是构造函数的原型对象
  • 构造函数的对象中有一个构造器(constructor)指向构造函数本身
  • 实例对象中的原型对象,__proto__,指向的是该构造函数的原型对象(prototype)
  • 构造函数的原型对象(prototype)中的方法是可以被实例对象直接访问的
  <script>
        //自定义构造函数
        function Person(name,age){
            this.age=age;
            this.name=name;
        }
        //通过原型添加方法
        Person.prototype.sayHi=function(){
            console.log("hello");
        }
        //实例化对象
        per=new Person("小明",20);
        console.dir(Person);
        console.dir(per);
    </script>

6、利用原型共享数据

  • 需要共享的数据可以写在原型中,可以是属性或者方法
  • 不影响共享的数据写在构造函数中,需要共享的数据写在原型中
    <script>
        //自定义构造函数
        function Student(name,age){
            this.name=name;
            this.age=age;
        }
        //通过原型添加相同的数据,实现共享
        Student.prototype.height="180cm";
        Student.prototype.weight="100kg";
        Student.prototype.sex="都是男的";
        
        //实例化对象
        stu1=new Student("关羽",30);
        stu2=new Student("刘备",31);
        stu3=new Student("张飞",29);
        console.log(stu1.height);//180cm
        console.log(stu2.weight);//100kg
        console.log(stu3.sex);//都是男的
    </script>

7、简单的原型写法

  • 格式:构造函数.prototype={  属性或者方法  }
  • 但是这种写法需要手动修改构造器的指向----constructor:构造函数名
   <script>
        //自定义构造函数
        function Student(name,age){
            this.name=name;
            this.age=age;
        }
        //通过原型添加相同的数据,实现共享
        //简单的原型写法(放进一个对象里)
        //但是必须要手动修改构造器的指向
        Student.prototype={
            constructor:Student,
            height:"180cm",
            weight:"100kg",
            sex:"都是男的"
        }
        
        //实例化对象
        stu1=new Student("关羽",30);
        stu2=new Student("刘备",31);
        stu3=new Student("张飞",29);
        console.log(stu1.height);//180cm
        console.log(stu2.weight);//100kg
        console.log(stu3.sex);//都是男的}
    </script>

8、原型中的方法是可以互相进行访问的

   <script>
        //自定义构造函数
        function Student(name,age){
            this.name=name;
            this.age=age;
        }
        //通过原型添加方法
        Student.prototype.eat=function(){
            console.log("吃饭");
        };
        Student.prototype.sleep=function(){
            console.log("睡觉");
            this.eat();//添加eat方法
        };
        Student.prototype.play=function(){
            console.log("玩球");
            this.sleep();//添加sleep方法
        };
        //实例化对象
        var per=new Student("小明",20);
        per.eat();//吃饭
        per.sleep();//睡觉 吃饭
        per.play();//玩球 睡觉 吃饭
    </script>

9、原型的层层搜索

  • 实例对象使用的属性或者方法,先在实例对象中找,找到了则直接使用
  • 找不到则去实例对象的__proto__指向的原型对象prototype中找,找到了使用
  • 找不到则报错
   <script>
        //自定义构造函数
        function Student(name,age){
            this.name=name;
            this.age=age;
            this.eat=function(){
               console.log("构造函数中的吃饭");
            }
        }
        //通过原型添加方法
        Student.prototype.eat=function(){
            console.log("原型中的吃饭");
        };
        //实例化对象
        var per=new Student("小明",20);
        per.eat();//构造函数中的吃饭
        //说明实例对象调用方法时,首先在构造函数中寻找这个方法,没有的话,再去原型__proto__去找这个方法
    </script>

10、为系统内置对象添加原型方法(相当于改变源码)

    <script>
    //例1:字符串中添加一个倒序字符串的方法
    String.prototype.myReverse=function(){
        for(var i=this.length-1;i>=0;i--){
           console.log(str[i]);
        }
    };
    var str="abcd123";
    str.myReverse();//3 2 1 d c b a
    //例2:数组内置对象添加一个方法sayHi
    Array.prototype.sayHi=function(){
        console.log("猴赛雷!!!")
    };
    var arr=[1,2,3];
    arr.sayHi();//猴赛雷!!!
    </script>

11、把局部变量变成全局变量------把局部变量给window就可以了

   <script>
        (function(){
            var num=10;
            //js是一门动态类型的原因,对象没有属性,点了就有了
            window.num=num;
        })();
        console.log(num);//10
        //结论:把局部变量给Window就可以变成全局变量
    </script>

12、案例:随机小方块(相当于贪吃蛇案例的食物)

    <div class="map" style=" 800px;height: 800px;background: #ccc;position: relative;"></div>
    <script>
    //产生随机对象的
    (function (window){
        //产生随机数的构造函数
        function Random(){

        }
        //在原型中添加方法
        Random.prototype.getRandom=function(min,max){
            return Math.floor(Math.random()*(max-min)+min);
        };
        //把random对象暴露给顶级对象window---->外部可以直接使用这个对象
        window.Random=new Random();//直接示例化对象
    })(window);
    //产生小方块对象
    (function(window){
        //选择器的方法获取元素对象
        var map=document.querySelector(".map");
        //小方块的构造函数
        function Food(width,height,color){
            //默认的小方块的高和宽
            this.width=width||20;
            this.height=height||20;
            //横坐标和纵坐标
            this.x=0;
            this.y=0;
            //小方块的背景颜色
            this.color=color;
            //小方块的元素
            this.element=document.createElement("div");
        }
        //初始化小方块的显示和效果及位置---显示在地图上
        Food.prototype.init=function(map){
            //设置小方块的样式
            var div=this.element;
            div.style.position="absolute";
            div.style.width=this.width+"px";
            div.style.height=this.height+"px";
            div.style.backgroundColor=this.color;
            //把小方块加到地图中
            map.appendChild(div);
            this.render(map);
        };
        //产生随机位置
        Food.prototype.render=function(map){
            //随机产生横坐标
            var x=Random.getRandom(0,map.offsetWidth/this.width)*this.width;
            var y=Random.getRandom(0,map.offsetHeight/this.height)*this.height;
            this.x=x;
            this.y=y;
            var div=this.element;
            div.style.left=this.x+"px";
            div.style.top=this.y+"px";
        };
        var fd=new Food(20,20,"red");
        fd.init(map);
        console.log(fd.x+"========"+fd.y);
    })(window);
    </script>

原文地址:https://www.cnblogs.com/EricZLin/p/9049002.html