• 谈谈我认识的js原型


      众所周知,JavaScript中是没有传统类的概念的,js通过原型链的方式实现继承。原型是js学习中的一大重点知识,在ES6出来之前,因为js不像php、java一样拥有类的写法,所以继承方式也就不像php、java一样通过关键字extends实现子类继承父类的方式,但是js有它独特的实现继承的方式,这种方式有:prototype、原型冒充、复制继承。

    1、prototype

      js中每个函数就是一个对象,每个对象都有自己的prototype属性,通过这个属性,可以指定某一类对象的原型

     function   Person(name,age,sex){
        this.name = name || " ", //设置默认值,如果传入实参,this.name的值就等于实参的值,否则this.name的值默认为 " "
        this.age    = age || 24,
        this.sex    = "男" || sex,
        this.say = function (){
          console.log("我会说话");
        },
        this.smile = function(){
          console.log("笑");
        },
        this.walk = function(){
          console.log("走路");
        }
      };
    
    function  Monkey(){
        this.type = "monkey";
    };
    var  oop = new Person();
    Monkey.prototype = oop;
    var  oom = new Monkey();
    //执行oom.say()输出 我会说话
    oom.say();

    oom对象并没有say()方法,为什么程序没有保存而且控制台还输出了 “我会说话”。因为oom对象的构造函数的prototype属性指向oop对象,表明由Monkey构造函数创建出来的一类对象,他们都具有共同的原型:oop对象。所以oom对象调用say()方法中,程序会默认先在oom对象中查找,如果没有找到这个属性,程序会沿着原型链往上寻找该属性。

    需要注意的是,js中new  构造函数()这个过程发生了如下的操作:

    a、创建空对象 { };

    b、this指向空对象{ };

    c、执行构造函数的函数体。

    在过程c中,如果你熟悉js的为对象添加属性的方式(对象名 属性),你会发现,过程c其实就是给这个空对象添加属性和方法的过程。

    构造函数名 。prototype = 对象 ,这个对象也可以是自定义的对象,在这个对象中定义了需要用到的方法和值。如下例子所示:

    function   op(){
      a = 3;
    };
    
    var  obj = {
      para : 1,
      say : function(){console.log("obj");}
    };
    //指定构造函数op的原型是obj对象;
    op.prototype = obj;
    
    //由构造函数op创建的oop对象能够调用对象obj中的方法
    var oop = new op();
    oop.say();

    2、原型冒充

      原型冒充的原理是通过call()与apply()函数改变当前对象的this的执行上下文。这话说的有点抽象,下面直接用例子解释:

     

     //函数
      function   increase(a , b){
        return   a+b;
      };
    
      function    reduce(a , b){
        return  a-b;
      }
      increase . call(reduce,1,2);  //输出3
    
      reduce . call(increase,1,2);  //输出-1
     
    解释 :对象A . call(对象B , 参数1 , 参数2  , ......参数n)中执行了这样的操作:
    
    a、修改对象A的this的指向,使其暂时指向对象B,参数1与参数2是传入对象B的实参。
    
    b、执行调用call()方法的对象。
    
    所以increase . call(reduce,1,2); 这一句相当于increase中this指向reduce,然后执行increase(1,2),所以最终结果输出3。
    
     //对象
    
    function person(name){
        this.name = name;
        this.say = function(){
        console.log(this.name);
        }
    };
        var op = new person("张三");
        op.say();
    
    function lisi(name){
        this.name = name;
    };
        var ls = new lisi("李四");
        op.say.call(ls);//this指向ls :op.say(){ console.log(ls.name) },执行op.say()方法,输出 李四

    op.say.call(ls)这句代码先是将say()函数体内的this指向ls,然后执行say()方法。op.say();这一步在正常情况下输出的结果应该是"张三",但是为什么却是“李四”了呢?原因是op.say.call(ls)这句代码将say()函数在程序解析到这句代码的位置时,this暂时指向对象ls,所以在op对象的say()体内的输出语句console.log(this.name)实际上是console.log(ls.name);

    3、复制继承

      复制继承的原理是,将对象以参数的形式传递到构造函数中,在构造函数中通过对象属性的方式(Objname . propertyname或者Objname[propername])访问盖对象的属性值,将值赋予当前对象的属性。

      

    function   Person(){
        this.name = "张三";
        this.age  = 24;
        this.sex  = "男"
    }
    
    function  children(per){
        this.name = per.name;
        this.age  = per.age;
        this.sex  = per.sex;
    
    }
    var   op = new  Person();
    //向children构造函数中传入op对象,在children函数内完成值的复制
    var   chi = new  children(op);
    console.log(chi.age);

     以上均是js原型继承的实现方式,在js这个海洋中,因为知识有限,所以博客还存在很多不足之处,希望更够跟大家多多交流学习。

  • 相关阅读:
    donet core 2.1 DateTime ToString() 方法 在不同平台返回的时间格式不一样?
    asp.net core 2.1 post 无法提交参数?
    重写$.ajax方法
    基于git 客户端使用shell工具
    NPOI 自定义单元格背景颜色-Excel
    Ubuntu 1604配置安装mysql8.0
    Fiddler拦截并修改移动端请求
    MFC路径层的使用(BeginPath和EndPath函数)
    MFC中设备描述表dc的使用
    不能从const char *转换为LPCWSTR --VS经常碰到
  • 原文地址:https://www.cnblogs.com/novice007/p/7764583.html
Copyright © 2020-2023  润新知