js-原型

原型

详细:原型

在JS里,万物皆对象。方法(Function)是对象,方法的原型(Function.prototype)是对象。因此,它们都会具有对象共有的特点。即:对象具有属性__proto__,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。

  • 可以将原型理解为对象的父亲,对象从原型对象继承来属性
  • 原型就是对象除了是某个对象的父母外没有什么特别之处
  • 所有函数的原型默认是 Object的实例,所以可以使用toString/toValues/isPrototypeOf 等方法的原因
  • 原型对象为多个对象共享属性或方法
    -如果对象本身不存在属性或方法将到原型上查找
    -使用原型可以解决,通过构建函数创建对象时复制多个函数造成的内存占用问题
    -原型包含 constructor 属性,指向构造函数
    -对象包含___proto___指向他的原型对象
 let xz = {
                render() {
                    //如果自己有这个方法,就不会调用原型里的方法
                    console.log('xz,render');
                }
            }
            //在xz的原型上添加这个方法,其他对象也会有,因为是将这个方法添加到了他父亲上
        xz.__proto__.render = function() {
            console.log('render');
        }
        let lsy = {}
        xz.render()
        lsy.render()
        console.log(xz);

对象里是有__proto__
一个函数里既有prototype也有__proto__
以下例为例:
其中当User为对象的时候,就是用__proto__
当User为函数的时候,就是prototype,
hd的__proto__和user的prototype 是同一个东西,也就是说在user.prototype中添加方法,hd可以使用,但是如果在user.__proto中添加方法,hd不能使用

        function User() {}
        User.__proto__.view = function() {
            console.log("User function view method");
        };
        // __proto__是用于对象
        // User.view(); //静态调用 
        //prototype是用于函数
        User.prototype.show = function() {
            console.log("后盾人");
        };
        let hd = new User();//hd为user的实例化对象
        //hd的__proto__和user的prototype 是同一个东西
        console.log(User.prototype == hd.__proto__); //true
        
        User.view()//User function view method
        hd.view() //报错
        hd.show();//后盾人
        

原型链

自定义对象的原型

Object.setPrototypeOf()

let hd = {
            name: 'hd'
        }
        let parent = {
            name: 'parent',
            show() {
                console.log('parent method:' + this.name);
            }
        }

        Object.setPrototypeOf(hd, parent)
        console.log(hd);
        hd.show() //parent method:hd
        parent.show() //parent method:parent
        console.log(Object.getPrototypeOf(hd));

通过对象找出他的构造函数在创建对象

  function User(name) {
            this.name = name,
                this.show = function() {
                    console.log('this:' + this.name);
                }

        }
        let xz = new User('xiaozhuo')

        function createByObject(obj, ...args) {
            const constructor = Object.getPrototypeOf(obj).constructor
            let fn = obj.__proto__.constructor
            console.log(fn == constructor); //true
            console.log(fn);
            return new fn(...args)


        }
        let lsy = createByObject(xz, 'luoshiyi')
        lsy.show()
        console.log(lsy);

isPrototypeOf和 instanceof 的区别

  • A.isPrototypeOf(B) 判断的是A对象是否存在于B对象的原型链之中
  • A instanceof B 判断的是B.prototype是否存在与A的原型链之中

所以就有下面的结论:

如果 A.isPrototypeOf(B) 返回true 则B instanceof A 一定返回true

使用call或者apply借用其他对象的原型

后盾人-借用原型

let xz = {
            name: 'xzzz',
            data: [33, 1, 2, 3, 45, 67, 888, 523]
        }

        Object.setPrototypeOf(xz, {
            car: function() {
                console.log('show car');
            },
            max: function() {
                // console.log(this.data);
                this.data.sort((a, b) => {
                    return b - a
                })
                return this.data[0]
            }
        })
        console.log(xz.max());

        let lsy = {
            name: 'luoshiyi',
            data: [, 111, 333, 22, 1, 55, 78, 999]
        }
        console.log(xz.max.call(lsy));

Dom节点借用数组原型

<body>
  <button message="后盾人" class="red">后盾人</button>
  <button message="hdcms">hdcms</button>
</body>
<script>
  let btns = document.querySelectorAll("button");
  btns = Array.prototype.filter.call(btns, item => {
    return item.hasAttribute("class");
  });
</script>

原型的继承

下例中:people的prototype继承user的property

		function user() {}
        user.prototype = {
            constructor: user,
            usershow: function() {

                console.log('继承成功user', this.name);
            }
        }
        let user1 = new user()
            // console.log(user1);

        function people(name) {
            this.name = name
            this.peopleshow = function() {
                console.log('peopleshow');
            }
        }
        people.prototype = {
            constructor: people,
            peopleshowpro: function() {
                console.log('peopleshowpro');
            }
        }

        //people.prototype.__proto__原本是指向最终的Object.property,现在把他改为user.prototype
        people.prototype.__proto__ = user.prototype
        let people1 = new people('xz')
        people1.usershow() //继承成功user xz
        people1.peopleshow() //peopleshow
        people1.peopleshowpro() //peopleshowpro

Object.create()

通过Object.create()实现原型的继承

  • Object.creat()方法创建一个新对象,新创建的对象的__proto__为creat()里的对象。
//使用Object.create是使Member.prototype.__proto__为User.prototype
Member.prototype = Object.create(User.prototype);
console.log(Member.prototype.__proto__ == User.prototype);//true

Member.prototype = User.prototype
console.log(Member.prototype == User.prototype);//true

使用第一个参数的对象,作为新对象的原型

  • 因为有时根据得到的对象获取构造函数,然后再创建新对象所以需要保证构造函数存在,但如果直接设置了 Admin.prototype 属性会造成constructor丢失,所以需要再次设置constructor值。
function User() {}
User.prototype.getUserName = function() {};

function Admin() {}
Admin.prototype = Object.create(User.prototype);
Admin.prototype.constructor = Admin;//需要重新设置constructor
Admin.prototype.role = function() {};

function Member() {}
Member.prototype = Object.create(User.prototype);
//这里就是Member.prototype.__proto__==User.prototype
console.log(Member.prototype.__proto__ == User.prototype);//true
Member.prototype.email = function() {};
console.log(new Admin());
console.log(new Member());

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

我们希望调用父类构造函数完成对象的属性初始化,但像下面这样使用是不会成功的。因为此时 this 指向了 window,无法为当前对象声明属性。

function User(name) {
  this.name = name;
  console.log(this); // Admin
}
User.prototype.getUserName = function() {
  return this.name;
};

function Admin(name) {
  User.call(this, name);
}
Admin.prototype = Object.create(User.prototype);

let xj = new Admin("向军大叔");
console.log(xj.getUserName()); //向军大叔

使用原型工厂封装继承

  function extend(sub, parent) {

            sub.prototype = Object.create(parent.prototype)
                // sub.prototype.constructor = sub
            Object.defineProperty(sub.prototype, 'constructor', {
                value: sub,
                enumerable: false
            })

        }

        function user(name, age) {
            this.name = name
            this.age = age
            this.show = function() {
                console.log(`${this.name}+${this.age}`);
            }
        }

        function people(...args) {
            user.apply(this, args)
        }

        extend(people, user)
        let xz = new people('xiaozhuo', 18)
        console.log(xz);
        xz.show()

使用Mixin模式实现多继承

这相当于将对象的prototype与要继承的对象进行合并,
注意:Object.assign()是浅拷贝

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

 		// function Credit() {}
        // Credit.prototype.total = function() {
        //     console.log("统计积分");
        // };
        //将原型对象里面的方法改写成对象里的方法
        const Credit = {
            total() {
                console.log("统计积分");
            }
        };
        const Request = {
            ajax() {
                console.log("请求后台");
            }
        };

        function Admin(...args) {
            User.apply(this, args);
        }
        extend(Admin, User); //Admin真正的继承User
        console.log(Admin.prototype.__proto__ == User.prototype); //ture
        Object.assign(Admin.prototype, Request, Credit); //将Admin.prototype与Request和Credit进行对象合并,如下图
        console.dir(Admin);
        let hd = new Admin("向军", 19);
        hd.show();
        hd.total(); //统计积分
        hd.ajax(); //请求后台

请添加图片描述

super关键字

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(this.__proto__.ajax()+ ",统计积分")
    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(); //请求后台
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值