• javascript原型深入解析1-prototype 和原型链、js面向对象


    1.用prototype 封装类

    创建的每个函数都有一个prototype(原型属性),他是个指针,指向的对象,这个对象的用途就是包含了这个类型所有实例共享的属性和方法。

    回味这句,想想java或者C++吧,如果func是class 类,类的类属性和类方法都放在了prototype中了

    var func = function (argument) {
      // body...
    };

     

    Ok,现在就用c++面向对象的思想建立个Person类,里面有一些类成员

    function Person(){
    
     }
    
     Person.prototype.say = function(first_argument) {
       // body...
       console.info('i say...')
    
     };
    
     Person.prototype.age = 10;
     var sy = new Person(); // new 会创建个对象,不加new 就是执行这个函数
    
    
     console.info(sy.age)
     sy.say()

    成功实现了面向对象,sy 可以say,还有了age,当然age不应该是类属性,

    Say和age 是所有 Person 所有实例共享的,假如age是数组,sy.age[1] = 10 会导致所有实例的age都变化

    2.原理:定义Person function,实例化一个Person,中间有啥奥秘

    定义:

    function Person(){
    
    }
    1. 只要创建个新函数,js引擎会根据一组特定的规则为该函数创建一个原型对象, prototype属性指向这个原型对象;
    2. 默认情况下,所有原型对象都会自动获取一个constructor(构造函数)属性,这个constructor指向了prototype属性所在的函数;

    实例化:

    new的过程拆分成以下三步:

    1. var p={}; 也就是说,初始化一个对象p
    2. p.__proto__ = Person.prototype;
    3. Person.call(p); 也就是说构造p,也可以称之为初始化p,过程中关键字 this 被设定为该实例。
    4. 返回实例
    function New (f) {
    
        var n = { '__proto__': f.prototype }; /*第1,2步*/
    
        return function () {
    
            f.apply(n, arguments);            /*第3步*/
    
            return n;                         /*第4步*/
    
        };
    
    }
    
    var p2 = New (Point)(10, 20);
    
    p2.print(); // 10 20
    
    console.log(p2 instanceof Point); // true

    sy = new Person(),创建一个新对象sy,sy实例的内部将包含一个Prototype类型的指针__proto__,指向Person函数的原型对象,实例sy和Person没直接关系,和Person.prototype才有直接关系

    这里我们可以发现,prototype太重要了

           

    sy.say() 看来是通过查询__proto__指向的原型来调用方法的;访问对象属性时,js会搜索改该属性,从实例sy开始,沿着原型搜索;

    需要注意的是sy.age = 100, 不会修改原型的值,而是给sy添加了个属性age,以后就屏蔽了原型的age,这点和python类似。当然你可以 delete sy.age,就可以重新访问到原型属性了。当然原型的属性age不属于实例,实例也delete不掉。

    有的浏览器无法访问__proto__,可以通过Person.prototype.isPrototypeOf(sy)  等于true,或者Object.getPrototypeOf(sy) == Person.prototype 判断原型和实例之间的关系s

    3. 类:现在我们来实现面向对象的封装功能

    function Person(name, age){
      this.name = name; // 调用new的时候,创建个新的this指向当前正在构造的新实例,其他时候的this都是指向调用者s
      this.age = age;
    }
    
    
    
    Person.prototype.say = function(first_argument) {
      console.info(this.name + ' say...')
    };
    
    var sy = new Person('suyuan', 26);
    sy.say()
    
    var zl = new Person('zhuli', 27)
    zl.say()

    一句话,方法用原型链,类属性(数据)用构造函数

    4.既然面向对象编程了,那么继承呢?

    Js中的函数没有声明,只有定义,所有不支持接口继承,那我们就用原型链来实现定义(实现)继承

    function Person(){
      this.live = true;
    }
    
    Person.prototype.say = function(first_argument) {// (4) Person的原型添加函数say
      console.info('i am ' + this.live)
    
    };
    
    
    
    function Man(){
      this.manLive = true;
    }
    
    var tmp_person = new Person();//(3) 实例tmp_person 的__proto__ 指向Person原型
    Man.prototype = tmp_person //(2) temp_person 这个对象有say方法,Man的原型(也就是temp_person)有say方法,Man实例化出来的对象sy当然有say
    
    var sy = new Man();//(1)
    sy.say()//(5)

    sy是Man实例,

    (1)sy的__proto__指向Man的原型,

    (2)Man原型指向Person的实例tmp_person,

    (3) tmp_person的__proto__指向Person原型,

    (4)Person原型有函数say

    (5)然后sy 就有了say方法。

    在此继承就实现了。

    更深入的了解,请看下一篇

     http://www.cnblogs.com/suyuan1573/p/proto.html

  • 相关阅读:
    关键两招就解决Wampserver 打开localhost显示IIS7图片问题
    死磕!Windows下Apache+PHP+phpmyadmin的配置
    宝塔linux面板运行jsp文件的配置工作
    Python关于self用法重点分析
    Atom窗口切换和放大或者缩小
    容易掉坑的地方The value for the useBean class attribute XXX is invalid
    JS 之如何在插入元素时插在原有元素的前面而不是末尾
    ul或者ol中添加li元素
    页面右下角广告
    getAttribute与setAttribute
  • 原文地址:https://www.cnblogs.com/suyuan1573/p/prototype.html
Copyright © 2020-2023  润新知