感谢: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>