原型与继承

获取对象的原型

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(); //请求后台
分情破爱始乱弃,流落天涯思别离。 如花似玉负情意,影如白昼暗自迷。 随风浮沉千叶落,行色匆匆鬓已稀。
原文地址:https://www.cnblogs.com/cshaptx4869/p/15038680.html