感谢:https://www.bilibili.com/video/av78687689?p=2
笔记

waht?

对象 》 原型 》》原型的原型

Object.create(null, … ) 可以创建 没有原型的 对象

原型

# 原型方法、对象方法的优先级

自己有 用自己的

# 函数 的原型

函数 和 函数原型 同一原型



但是函数 还有 一个原型


原型 关系 、 属性继承

Object.prototype 是顶级原型

系统构造函数的原型 体现

自定义 对象的 原型设置 setPrototypeOf


下面 的 this 始终是 调用的对象,即这里是 parent

getPrototypeOf

原型 constructor 引用

给我一个对象,还你一个世界

function User(name) {
    this.name = name ; 
}

let hd = new User("厚度的男人") ; 
console.log(hd) ; 
function createByObject(obj,...args) {
    const constructor = Object.getPrototypeOf(obj).constructor;
    return new constructor(...args);
}
let xj = createByObject(hd, '向军') ;
console.log(xj);

原型链 总结



这就实现继承的效果了

原型链检测之 instanceof 【prototype】

prototype / setPrototypeOf





# isPrototypeOf 判断长辈、设置长辈

let a = {} ; 
let b = {} ;
let c = {} ; 
console.log(Object.prototype.isPrototypeOf(a))
console.log(b.__proto__.isPrototypeOf(a))
Object.setPrototypeOf(a,b) ; 
Object.setPrototypeOf(b,c) ;
console.log(b.isPrototypeOf(a)) ; 
console.log(c.__proto__.isPrototypeOf(a))

# 属性的 检查

in

in 不单只检查对象,还检测对象的原型链(下面)

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

hasOwnProperty - in 的遍历

(下面)只要看本类的 , 用 hasOwnProperty

let a = {url:'houdunren'};
let b = {name:'后盾人'};

Object.setPrototypeOf(a,b) ;

console.log(a.hasOwnProperty('url'))

所以 , 我们遍历时候,有的 工具会自动加上(下面)

let a = {url:'houdunren'};
let b = {name:'后盾人'};

Object.setPrototypeOf(a,b) ;

for (const key in object) {
    if (object.hasOwnProperty(key)) {
        const element = object[key];
        
    }
}

这代表了,只遍历本类的 属性

方法借用!

# 借用原型

借用原型 功能

let hd = {
    data: [1,2,3,4,5,6]
}

Object.setPrototypeOf(hd, {
    max() {
        return this.data.sort((a,b) => b-a)[0];
    }
})

console.log(hd.max())


apply - 借用方法

文章 - 《proxy apply ***》 :https://blog.csdn.net/LawssssCat/article/details/104190288#Proxy__1127

https://www.jianshu.com/p/aa2eeecd8b4f
apply - 多个参数 视为 1个
call - 多个参数 视为 多个

let hd = {
    data: [1,2,3,4,5,6]
}

Object.setPrototypeOf(hd, {
    max() {
        return this.data.sort((a,b) => b-a)[0];
    }
})

console.log(hd.max())


let xj = {
    lessons:{js:87, php: 63, node: 99, linux: 88} ,
    get data() {
        return Object.values(this.lessons) ;
    }
}; 

let result = hd.max.apply(xj)
console.log(result)

# 借用 Math.max

let arr = [1,2,3,4,5]

console.log(Math.max(...arr)); //把数组展开



let hd = {
    data: [1,2,3,4,5,6]
}

console.log(Math.max.apply(null, hd.data))

let xj = {
    lessons:{js:87, php: 63, node: 99, linux: 88} 
}; 

console.log(Math.max.apply(null, Object.values(xj.lessons)))

# 借用 filter

    let arr = [1,3,33,44,53] ;
   let res = arr.filter(item => {
       return item>=39 ;
   })

   console.log(res)

   let btns = document.querySelectorAll('button') ;
   console.log(btns.filter)

   btns = [].filter.call(btns, item => { //只要能找到 filter 方法即可 如:Array.prototype
       return item.hasAttribute('class') ;
   })

   console.log(btns[0].innerHTML)
</script>

# 不重复创建 方法内存

一般是把方法放在原型里面,而不是单独写入对象

    function User(name) {
        this.name = name ;
    }
    User.prototype.show = function(){
        console.log(this.name) ;
    }
    let lisi = new User("李四");
    let xj = new User("向军");

    console.log(lisi) ;
    console.log(xj)

方法多了 可以这样写 (下图)

function User(name) {
        this.name = name ;
    }
    User.prototype = {
        constructor: User , //保证通过原型 也能找到构造函数
        show() {
            console.log(this.name) ;
        },
        get() {
            return  this.name;
        }
    }
    let lisi = new User("李四");
    let xj = new User("向军");

    console.log(lisi) ;
    console.log(xj)

    lisi.show() ;
    console.log(lisi.get())

# this 永远指向调用的对象

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

# 避免原型的乱用

不要直接在 Object 原型上加东西

Object.create

最开始,没有 __proto___

let user = {
        show() {
            return this.name;
        }
    }
    //定义对象的原型,不能获取
    let hd = Object.create(user, {//1,定义对象原型。2,定义对象特征
        name: {
            value: '后盾人'
        }
    })
    console.log(hd.show())
    console.log(hd)

想象下,没有 __proto___ ,我们就没法获取原型

后来 有了 __proto___ (不是官方的,是浏览器厂商自主研发出来的)

直接设置(获取)即可

let user = {
        show() {
            return this.name;
        }
    }
    //定义对象的原型,不能获取
    let hd = {name: '后盾人'}
    hd.__proto__ =user ; 
    console.log(hd.show())
    console.log(hd)
    console.log(hd.__proto__)

官方的 (标准)

上面讲的 create 只是定义原型
下面是 官方给出的 新方法,设置/获取原型(更佳强大)

  • Object.setPrototypeOf()
  • Object.getPrototypeOf()

__proto__ 原来是访问器?

有神器的现象

    let hd = {name:'后盾人'};
    hd.__proto__ = {
        show(){
            console.log(this.name)
        }
    }
    hd.__proto__ = 1 ; 
    hd.show();

后面设置的 hd.__proto__ = 1 ; 没有生效(生效了 理应会报错)

为什么会这样呢?

前面 的访问器 告诉了答案

(这种情况,只能是访问器的功能)

看下面的仿照例子

    let hd = {
        action: {} ,
        get proto() {
            return this.action ;
        },
        set proto(obj) {
            if(obj instanceof Object) {
                this.action = obj ;
            }
        }
    }
    hd.proto = {view: function() {}} ; 
    hd.proto = 'abc' ;
    console.log(hd.proto)

看下面

    let hd = {} ; 
    console.dir(hd)

如何 重置 __proto__

let hd = {} ; 
hd = Object.create(null);
hd.__proto__ = 'haha' ;
console.log(hd);

继承

# Admin.prototype.__proto__ = User.prototype

只要 让 能使用 父类原型方法,且保留本类原型 方法 ,即为继承

    // 原型的继承,而不是改变构造函数的原型
    // User
    function User() {
    }
    User.prototype.role = function() {
        console.log('user');
    }

    // admin
    function Admin() {}
    Admin.prototype.__proto__ = User.prototype;
    Admin.prototype.role = function() {
        console.log('admin');
    }

    // member
    function Member() {}
    Member.prototype.__proto__ = User.prototype ; 
    Member.prototype.role = function() {
        console.log("member") ;
    }

    let u = new User() ;
    let a = new Admin() ;
    let m = new Member() ;

    u.role() ;
    a.role() ;
    m.role() ;


# 继承对对象实例 的影响

用 create 方法 继承 有时会出现问题

    function User() {} 
    User.prototype.role = function() {
        console.log("user") ;
    }
    function Admin() {}
    let a = new Admin() ;
    Admin.prototype = Object.create(User.prototype) ;
    a.role();


这时(如果 一定 实例要先创建),要 换一种方式继承

    function User() {} 
    User.prototype.role = function() {
        console.log("user") ;
    }
    function Admin() {}
    let a = new Admin() ;
    Admin.prototype.__proto__ = User.prototype
    a.role();

# 使用 Object.create 的问题1

根据构造函数 (前面说了)

    function Hd() {}
    let obj = new Hd() ;
    console.log(obj.__proto__.constructor == Hd);

看下面 代码

    function User() {} ;
    function Admin() {} ; 
    Admin.prototype = Object.create(User.prototype) ; 
    console.log(Admin.prototype.constructor);
    console.log(Admin.prototype.constructor==User.prototype.constructor)
    console.dir(Admin)

这里的 console.log(Admin.prototype.constructor); 其实指向的 是 User 的 Constructor

所以 ,用 Object.create 的时候,要注意 加上下面代码

    function User() {} ;
    function Admin() {} ; 
    Admin.prototype = Object.create(User.prototype) ; 
    Admin.prototype.constructor = Admin ; 
    console.log(Admin.prototype.constructor==User.prototype.constructor);
    console.dir(Admin)

# 使用 Object.create 的问题2

先看 子类 原型的 属性特征

    function User() {} ;
    User.prototype.name = function() {
        console.log("user");
    }
    function Admin() {} ;
    Admin.prototype = Object.create(User.prototype) ;
    Admin.prototype.constructor = Admin ; 
    console.log(Admin.prototype)
    console.log(Object.getOwnPropertyDescriptors(Admin.prototype)) // 看这个对象的属性特征

writable: 可修改,
enumerable: 可遍历 / 直接查看,
configurable: 添加 / 删除 属性

可以看到,这是可遍历的

这会导致一个问题

forin 的时候 会看到 constructor (下面例子)

    function User() {} ;
    User.prototype.name = function() {
        console.log("user");
    }
    function Admin() {} ;
    Admin.prototype = Object.create(User.prototype) ;
    Admin.prototype.constructor = Admin ; 
    console.log(Admin.prototype)
    console.log(Object.getOwnPropertyDescriptors(Admin.prototype)) // 看这个对象的属性特征

    let a = new Admin() ;
    for(const key in a) {
        console.log(key)
    }

因此 要改成这样(下面)

    function User() {} ;
    User.prototype.name = function() {
        console.log("user");
    }
    function Admin() {} ;
    Admin.prototype = Object.create(User.prototype) ;
    //Admin.prototype.constructor = Admin ; 
    Object.defineProperty(Admin.prototype, "constructor", { // <- 改了这里!
        value: Admin,
        enumerable: false 
    })
    console.log(Admin.prototype)
    console.log(Object.getOwnPropertyDescriptors(Admin.prototype)) // 看这个对象的属性特征

    let a = new Admin() ;
    for(const key in a) {
        console.log(key)
    }

# 继承:方法重写

    function User() {}
    User.prototype.show = function() {
        console.log('user') ;
    };
    function Admin() {} 
    Admin.prototype = Object.create(User.prototype);
    Admin.prototype.constructor = Admin ;
    Admin.prototype.show = function() {
        console.log("admin") ;
    }
    let hd = new Admin() ;
    hd.show() ;

# 继承:多态

    'use strict';
    function User() {}
    User.prototype.show = function() {
        console.log(this.description());
    }

    function Admin() {} ;
    Admin.prototype = Object.create(User.prototype) ;
    Admin.prototype.description = function() {
        return "管理员";
    }

    function Member() {} ;
    Member.prototype = Object.create(User.prototype) ;
    Member.prototype.description = function() {
        return '会员' ;
    }

    function Enterprise() {} ;
    Enterprise.prototype = Object.create(User.prototype);
    Enterprise.prototype.description = function() {
        return '企业' ;
    }

    for(const iterator of [new Admin(), new Member(), new Enterprise()]) {
        iterator.show();
    }

# 借用父类构造

    function User(name, age) {
        this.name = name ; 
        this.age = age; 
    } ;
    User.prototype.show = function() {
        console.log(this.name, this.age) ;
    } ;

    function Admin(name, age) { //方法
        User.call(this, name, age) ;
    } ;
    Admin.prototype = Object.create(User.prototype);
    let xj = new Admin('向军', 18) ;
    xj.show() ;

    function Member(...args) { //方法 优化
        User.apply(this, args) ;
    }
    Member.prototype = Object.create(User.prototype) ;
    let m = new Member("哈哈", 100) ;
    m.show();

# 封装 extend :原型工厂

上面继承太繁琐,我们把 继承过程封装成一个方法 extend

    function extend(sub, sup) {
        sub.prototype = Object.create(sup.prototype);
        Object.defineProperty(sub.prototype, 'constructor', {
            value: sub, 
            enumerable: false 
        })
    }

    function User(name, age) {
        this.name = name ; 
        this.age = age; 
    } ;
    User.prototype.show = function() {
        console.log(this.name, this.age) ;
    } ;

    function Admin(name, age) { //方法
        User.call(this, name, age) ;
    } ;
    extend(Admin, User) ;
    let xj = new Admin('向军', 18) ;
    xj.show() ;

    function Member(...args) { //方法 优化
        User.apply(this, args) ;
    }
    extend(Member, User)
    let m = new Member("哈哈", 100) ;
    m.show();

# 封装:对象工厂

视频:https://www.bilibili.com/video/av78687689?p=33

    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();

# assign 实现多继承(接口)

    const Address = {
        getAddress() { 
            let addr = this.addr?this.addr: '地球';
            console.log(`获取收货地址:${addr}`);
        },
        setAddress(addr) {
            this.addr = addr ; 
        }
    }
    const Credit = {
        total() {
            console.log('统计积分')
        }
    }
    const Request = {
        ajax() {
            console.log('请求后台')
        }
    }
    function extend(sub, sup) {
        sub.prototype = Object.create(sup.prototype);
        Object.defineProperty(sub.prototype, 'constructor', {
            value: sub, 
            enumerable: false
        })
    }

    function User(name, age) {
        this.name = name ; 
        this.age = age ; 
    }
    User.prototype.show = function() {
        console.log(this.name, this.age);
    }

    function Admin(name, age) {
        User.call(this, name, age);
    }
    extend(Admin, User);
    Admin.prototype.ajax = Request.ajax; // 单个
    Admin.prototype = Object.assign(Admin.prototype, Credit, Address) // 批量

    let admin = new Admin('向军', 189);
    admin.show()
    admin.ajax();
    admin.setAddress('月球')
    admin.getAddress();

# super

视频:https://www.bilibili.com/video/av78687689?p=36


    const Address = {
        getAddress() { 
            let addr = this.addr?this.addr: '地球';
            console.log(`获取收货地址:${addr}`);
        },
        setAddress(addr) {
            this.addr = addr ; 
        }
    }
    const Request = {
        ajax() {
            return '请求后台'
        }
    }
    const Credit = {
        __proto__: Request, //this.__proto__ = super 且不会像this那样随意变
        total() {
            console.log(super.ajax() + '统计积分')
        }
    }
    function extend(sub, sup) {
        sub.prototype = Object.create(sup.prototype);
        Object.defineProperty(sub.prototype, 'constructor', {
            value: sub, 
            enumerable: false
        })
    }

    function User(name, age) {
        this.name = name ; 
        this.age = age ; 
    }
    User.prototype.show = function() {
        console.log(this.name, this.age);
    }

    function Admin(name, age) {
        User.call(this, name, age);
    }
    extend(Admin, User);
    Admin.prototype.ajax = Request.ajax; // 单个
    Admin.prototype = Object.assign(Admin.prototype, Credit, Address) // 批量

    let admin = new Admin('向军', 189);
    admin.show()
    admin.total() ;
    admin.setAddress('月球')
    admin.getAddress();


# 例子:选项卡

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style> .tab1, .tab2{ width: 400px; } </style>
</head>
<body>

    <main class="tab1">
        <nav>
            <a href="javascript:;">后端认</a><!--阻止转跳-->
            <a href="javascript:;">hdcms</a>
        </nav>
        <section>1</section>
        <section>2</section>
    </main>
    <main class="tab2">
        <nav>
            <span href="javascript:;">后端认</span><!--阻止转跳-->
            <span href="javascript:;">hdcms</span>
        </nav>
        <section>1</section>
        <section>2</section>
    </main>
</body>
<script> function extend(sub, sup) { sub.prototype = Object.create(sup.prototype) ; Object.defineProperty(sub.prototype, 'constructor' , { value: sub, enumerable: false }) } function Animation() {} ; Animation.prototype.show = function() { this.style.display = 'block' ; } Animation.prototype.hide = function() { this.style.display = 'none' ; } Animation.prototype.background = function(color) { this.style.backgroundColor = color ; } function Tab(el, args) { args=Object.assign({link:'a', section:'section', callback:null},args) this.tab = document.querySelector(el); this.links = this.tab.querySelectorAll(args['link']); this.sections = this.tab.querySelectorAll(args['section']); this.callback = args['callback']; } extend(Tab, Animation) Tab.prototype.run = function() { this.bindEvent() ; this.reset() ; this.action(0) ; } Tab.prototype.bindEvent = function() { this.links.forEach((el,i) => { el.addEventListener('click', () => { this.reset(); this.action(i); if(this.callback) this.callback() ; }) }); } Tab.prototype.action = function(i) { this.background.call(this.links[i], '#e67e22'); this.show.call(this.sections[i]) ; } Tab.prototype.reset = function() { this.links.forEach((el, i) => { this.background.call(this.links[i], '#95a5a6') this.hide.call(this.sections[i]) ; }) } new Tab('.tab1').run() ; new Tab('.tab2', { link: 'span' , callback: function() { console.log('后盾人') } }).run() ; </script>
</html>