• 原型与继承


    获取对象的原型

    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(); //请求后台
    
    分情破爱始乱弃,流落天涯思别离。 如花似玉负情意,影如白昼暗自迷。 随风浮沉千叶落,行色匆匆鬓已稀。
  • 相关阅读:
    Java
    Java
    SpringBoot
    面对 DDoS 攻击,我们能做些什么?
    instanceof运算符的实质:Java继承链与JavaScript原型链
    从λ演算到函数式编程聊闭包(1):闭包概念在Java/PHP/JS中形式
    JIT-动态编译与AOT-静态编译:java/ java/ JavaScript/Dart乱谈
    JS遍历循环方法性能对比:for/while/for in/for of/map/foreach/every
    线程池的使用示例-批量查询
    国企离职鸡飞狗跳记
  • 原文地址:https://www.cnblogs.com/cshaptx4869/p/15038680.html
Copyright © 2020-2023  润新知