zoukankan      html  css  js  c++  java
  • 原型与继承

    获取对象的原型

    Object.getPrototypeOf()

    let hd = {};
    let xj = {};
    console.log(Object.getPrototypeOf(hd) == Object.getPrototypeOf(xj));//true
    console.log(Object.getPrototypeOf(hd) == Object.prototype);//true
    

    创建对象并指定原型

    Object.create();
    创建一个新对象,第一个参数是这个对象的原型,第二个参数用以对对象的属性进行进一步描述。

    //创建一个没有原型的对象
    let hd = Object.create(null, {
        name: {
            value: '后盾人'
        }
    });
    console.log(Object.getPrototypeOf(hd));//null
    

    原型方法与对象方法优先级

    如果对象自己有方法,则优先执行自己的方法

    Object.prototype.render = function() {
        console.log('parent');
    };
    
    let hd = {
    	render() {
            console.log('child');
        }
    };
    
    hd.render();//child
    

    函数拥有多个长辈

    函数拥有多个原型; 函数既是对象又是构造函数

    函数作为构造函数使用时,会给创建的对象自动指定一个原型对象 User.prototype

    function User(){}
    let hd = new User();
    console.log(hd.__proto__ === User.prototype);//true
    

    函数作为对象使用时,可以使用 User.__proto__ 中的属性和方法。服务于函数自己

    function User(){}
    User.__proto__.view = function() {
        console.log('view');
    };
    User.view();//view
    

    原型关系详解

    原型也是个对象,也会有自己的父级。

    User.prototype.__proto__ 指向 Object.prototype
    User.__proto__ .__proto__ 指向 Object.prototype

    Object.prototype 没有原型,指向 null

    function User(){}
    Object.prototype.show = function(){
        console.log('show');
    };
    User.show();//show
    (new User()).show();//show
    console.log(User.prototype.__proto__ === Object.prototype);//true
    console.log(User.__proto__.__proto__ === Object.prototype);//true
    console.log(User.prototype.__proto__ === User.__proto__.__proto__);//true
    console.log(Object.prototype.__proto__ === null);//true
    

    系统构造函数的原型体现

    let arr = [];
    console.log(arr.__proto__ == Array.prototype);//true
    
    let str = '';
    console.log(str.__proto__ == String.prototype);//true
    

    自定义对象的原型设置

    Object.setPrototypeOf();

    let hd = {name: 'hd'};
    let parent = {name: 'parent'};
    Object.setPrototypeOf(hd, parent);
    

    原型中的 constructor 引用

    作用是,通过原型找到他的构造函数。

    function User(){}
    console.log(User.prototype.constructor == User);//true
    //改变原型是 constructor 属性得加上,否则无法找到他的构造函数
    User.prototype = {
        constructor: User,
        show() {
            console.log('show');
        }
    }
    

    根据对象创建新对象

    constructor 属性。

     function User(name) {
         this.name = name;
         this.show = function () {
             console.log(this.name);
         }
     }
    let hd = new User('后盾人');
    hd.show();//后盾人
    
    function createByObject(obj, ...args) {
        const constructor = Object.getPrototypeOf(obj).constructor;
        return new constructor(...args);
    }
    let xj = createByObject(hd, '向军');
    xj.show();//向军
    

    原型链

    let a = {
        name: 'a'
    };
    let c = {
        name: 'c'
    };
    let b = {
        name: 'b',
        show() {
            console.log(this.name);
        }
    };
    Object.setPrototypeOf(a, b);
    Object.setPrototypeOf(c, b);
    a.show(); //a
    c.show(); //c
    

    原型链检测

    instanceof

    检测一个对象的原型链上是否有构造函数的prototype。

    function User(){}
    let hd = new User();
    console.log(hd instanceof User);//true
    console.log(hd instanceof Object);//true
    

    isPrototypeOf

    检测一个对象是否在另一个对象的原型链上。

    let a = {name: 'a'};
    let b = {name: 'b'};
    let c = {name: 'c'};
    console.log(b.isPrototypeOf(a));//false
    Object.setPrototypeOf(a, b);
    Object.setPrototypeOf(b, c);
    console.log(b.isPrototypeOf(a));//true
    console.log(c.isPrototypeOf(a));//true
    

    属性检测

    in

    不仅检测当前对象,还会检测原型链上的属性。

    let a = {url: 'houdunren'};
    let b = {name: '后盾人'};
    Object.prototype.web = 'hdcms.com';
    console.log('web' in a);//true
    

    hasOwnProperty

    仅检测当前对象。

    let a = {url: 'houdunren'};
    let b = {name: '后盾人'};
    Object.prototype.web = 'hdcms.com';
    console.log(a.hasOwnProperty('web'));//false
    

    借用原型链

    callapply

    //#1
    let hd = {
        data: [1, 2, 3, 34, 5, 7]
    };
    Object.setPrototypeOf(hd, {
        max(data) {
            return data.sort((a, b) => b-a)[0]; 
        }
    });
    let xj = {
        lessons: {
            js: 87,
            php: 63,
            node: 99,
            linux: 88
        }
    };
    console.log(hd.max.call(null, Object.values(xj.lessons)));//99
    
    //#2
    let hd = {
        data: [1, 2, 3, 34, 5, 7]
    };
    console.log(Math.max.apply(null, hd.data)); //34
    let xj = {
        lessons: {
            js: 87,
            php: 63,
            node: 99,
            linux: 88
        }
    };
    console.log(Math.max.apply(null, Object.values(xj.lessons))); //99
    

    DOM节点借用Array原型方法

    <button message="后盾人" class="red">后盾人</button>
    <button message="hdcms">hdcms</button>
    <script>
        let btns = document.querySelectorAll('button');
        btns = Array.prototype.filter.call(btns, function (item) {
            return item.hasAttribute('class');
        });
        console.log(btns[0].innerHTML);//后盾人
    </script>
    

    合理的构造函数方法声明

    可以把公用的方法声明在构造函数的原型prototype上,减少额外内存开销。

    //#1
    function User(name) {
        this.name = name;
    }
    User.prototype.show = function () {
        console.log(this.name);
    }
    User.prototype.get = function () {
        console.log('...get');
    }
    let lisi = new User('李四');
    let xj = new User('向军');
    lisi.show();//李四
    xj.show();//向军
    
    //#2
    function User(name) {
        this.name = name;
    }
    User.prototype = {
        constructor: User,
        show: function () {
            console.log(this.name);
        },
        get: function () {
            console.log('...get');
        }
    }
    let lisi = new User('李四');
    let xj = new User('向军');
    lisi.show(); //李四
    xj.show(); //向军
    

    this 和原型没有关系

    this 永远指向调用属性的对象。

    let hd = {
        name: '后盾人'
    };
    let User = {
        name: '向军',
        show() {
            console.log(this.name);
        }
    }
    Object.setPrototypeOf(hd, User);
    hd.show();//后盾人
    

    不要滥用原型

    不建议在系统的原型链上增加方法。

    <button onclick="this.hide()">点我隐藏</button>
    <script src="a.js"></script>	
    <script src="b.js"></script>
    
    a.js
    Object.prototype.hide = function() {
        this.setAttribute("hide", true);
    }
    
    b.js
    Object.prototype.hide = function() {
        this.style.display = 'none';
    }
    

    Object.create 和 __proto__

    Object.create 可以定义对象的原型,但是没有提供获取的方法。

    而非标准的(浏览器厂商提供) __proto__ 既可以设置也可以获取。__proto__ 其实是一个 getter 和 setter,只能设置为对象类型(原型的上有做限制)。

    使用 Object.setPrototypeOf 和 Object.getPrototypeOf 代替 __proto__。

    改变构造函数原型并不是继承

    function User() {}
    User.prototype.name = function () {
        console.log('user.name');
    }
    
    function Admin() {}
    //改变了构造函数的原型
    Admin.prototype = User.prototype;
    Admin.prototype.role = function() {
        console.log('admin.role');
    }
    
    function Member() {}
    Member.prototype = User.prototype;
    Member.prototype.role = function() {
        console.log('member.role');
    }
    
    let a = new Admin();
    let m = new Member();
    a.role();//member.role
    m.role();//member.role
    

    继承是原型的继承

    #1
    function User() {}
    User.prototype.name = function () {
        console.log('user.name');
    }
    
    function Admin() {}
    Admin.prototype.__proto__ = User.prototype;
    Admin.prototype.role = function() {
        console.log('admin.role');
    }
    
    function Member() {}
    Member.prototype.__proto__ = User.prototype;
    Member.prototype.role = function() {
        console.log('member.role');
    }
    
    let a = new Admin();
    let m = new Member();
    a.role();//admin.role
    a.name();//user.name
    m.role();//member.role
    m.name();//user.name
    
    #2
    function User() {}
    User.prototype.name = function () {
        console.log('user.name');
    }
    
    function Admin() {}
    Admin.prototype = Object.create(User.prototype, {
        constructor: {
            value: Admin
        }
    });
    Admin.prototype.role = function() {
        console.log('admin.role');
    }
    
    function Member() {}
    Member.prototype = Object.create(User.prototype, {
        constructor: {
            value: Member
        }
    });
    //Admin.prototype.constructor = Member;
    Member.prototype.role = function() {
        console.log('member.role');
    }
    
    let a = new Admin();
    let m = new Member();
    a.role();//admin.role
    a.name();//user.name
    m.role();//member.role
    m.name();//user.name
    

    方法重写和父属性访问

    function User() {}
    User.prototype.show = function () {
        return 'user.show';
    }
    
    function Admin() {}
    Admin.prototype = Object.create(User.prototype, {
        constructor: {
            value: Admin
        }
    });
    Admin.prototype.show = function() {
        return User.prototype.show() + '|admin.show';
    }
    
    let a = new Admin();
    console.log(a.show());//user.show|admin.show
    

    面向对象的多态

    function User() {}
    User.prototype.show = function () {
        console.log(this.description());
    }
    
    function Admin() {}
    Admin.prototype = Object.create(User.prototype, {
        constructor: {
            value: Admin
        }
    });
    Admin.prototype.description = function() {
        return '管理员';
    }
    
    function Member() {}
    Member.prototype = Object.create(User.prototype, {
        constructor: {
            value: Member
        }
    });
    Member.prototype.description = function() {
        return '会员';
    }
    
    let a = new Admin();
    let m = new Member();
    a.show();//管理员
    m.show();//会员
    

    使用父类构造函数初始属性

    function User(name, age) {
        this.name = name;
        this.age = age;
    }
    User.prototype.show = function() {
        console.log(this.name, this.age);
    }
    
    function Admin(...args) {
        User.apply(this, args)
    }
    Admin.prototype = Object.create(User.prototype, {
        constructor: {
            value: Admin
        }
    });
    
    function Member(...args) {
        User.apply(this, args)
    }
    Member.prototype = Object.create(User.prototype, {
        constructor: {
            value: Member
        }
    });
    
    let xj = new Admin('向军', 18);
    let lisi = new Member('李四', 19);
    xj.show();//向军 18
    lisi.show();//李四 19
    

    封装继承

    #1
    function extend(sub, sup) {
        sub.prototype = Object.create(sup.prototype, {
            constructor: {
                value: Member
            }
    	});
    }
    
    function User(name, age) {
        this.name = name;
        this.age = age;
    }
    User.prototype.show = function() {
        console.log(this.name, this.age);
    }
    
    function Admin(...args) {
        User.apply(this, args)
    }
    
    function Member(...args) {
        User.apply(this, args)
    }
    
    extend(Admin, User);
    extend(Member, User);
    let xj = new Admin('向军', 18);
    let lisi = new Member('李四', 19);
    xj.show();//向军 18
    lisi.show();//李四 19
    
    #2
    function User(name, age) {
        this.name = name;
        this.age = age;
    }
    User.prototype.show = function() {
        console.log(this.name, this.age);
    }
    
    function admin(name, age) {
        const instance = Object.create(User.prototype);
        User.call(instance, name, age);
        return instance;
    }
    let hd = admin('向军', 18);
    hd.show();//向军 18
    

    使用 mixin 实现多继承

    mixin 类是一个包含许多供其它类使用的方法的类。

    mixin 类不用来继承做为其它类的父类。

    function extend(sub, sup) {
      sub.prototype = Object.create(sup.prototype);
      sub.prototype.constructor = sub;
    }
    
    function User(name, age) {
      this.name = name;
      this.age = age;
    }
    User.prototype.show = function() {
      console.log(this.name, this.age);
    };
    
    const Credit = {
      total() {
        console.log("统计积分");
      }
    };
    
    const Request = {
      ajax() {
        console.log("请求后台");
      }
    };
    
    function Admin(...args) {
      User.apply(this, args);
    }
    extend(Admin, User);
    Object.assign(Admin.prototype, Request, Credit);
    let hd = new Admin("向军", 19);
    hd.show();
    hd.total(); //统计积分
    hd.ajax(); //请求后台
    

    super 关键字

    super 是在 mixin 类的原型中查找,而不是在 User 原型中

    function extend(sub, sup) {
      sub.prototype = Object.create(sup.prototype);
      sub.prototype.constructor = sub;
    }
    
    function User(name, age) {
      this.name = name;
      this.age = age;
    }
    User.prototype.show = function() {
      console.log(this.name, this.age);
    };
    
    const Request = {
      ajax() {
        return "请求后台";
      }
    };
    
    const Credit = {
      __proto__: Request,
      total() {
        console.log(super.ajax() + ",统计积分");
      }
    };
    
    function Admin(...args) {
      User.apply(this, args);
    }
    extend(Admin, User);
    Object.assign(Admin.prototype, Request, Credit);
    let hd = new Admin("向军", 19);
    hd.show();
    hd.total(); //统计积分
    hd.ajax(); //请求后台
    
    分情破爱始乱弃,流落天涯思别离。 如花似玉负情意,影如白昼暗自迷。 随风浮沉千叶落,行色匆匆鬓已稀。
  • 相关阅读:
    windwos8.1英文版安装SQL2008 R2中断停止的解决方案
    indwows8.1 英文版64位安装数据库时出现The ENU localization is not supported by this SQL Server media
    Server Tomcat v7.0 Server at localhost was unable to start within 45 seconds
    SQL数据附加问题
    eclipse,myeclipse中集合svn的方法
    JAVA SSH 框架介绍
    SSH框架-相关知识点
    SuperMapRealSpace Heading Tilt Roll的理解
    SuperMap iserver manage不能访问本地目的(IE9)
    Myeclipse中js文件中的乱码处理
  • 原文地址:https://www.cnblogs.com/cshaptx4869/p/15038680.html
Copyright © 2011-2022 走看看