目录
1 面向对象与面向过程
2 原型对象 prototype
3 在内置对象中添加方法
4 constructor 属性
5 实例对象原型 __proto__
6 原型继承
7 原型链与instanceof
7.1 原型链
7.2 instanceof
8 案例-模态框
1 面向对象与面向过程
编程思想有 面向过程 与 面向对象,我们举个把大象从冰箱中拿出来的例子
面向过程就是 开冰箱门->把大象拿出来->关冰箱门 这三个步骤的代码自己写
面向对象就是 找一个会 开冰箱门->把大象拿出来->关冰箱门 的人,写代码的时候只写找人这一步(封装有可能得自己封装)
简单理解就是 面向对象将过程封装成一个整体,每次使用的时候使用整体。面向过程每次使用的时候使用若干个过程
面向对象有三个特性,封装性,继承性,多态性
我们通过下面这个图可以简单理解一下
面向过程与面向对象各有千秋,前端主要用面向过程
2 原型对象 prototype
prototype是构造函数的一个属性,实例对象中没有prototype
JS中通过构造函数体现面向对象的封装性
在构造函数中封装方法会造成内存浪费,因为用构造函数中创造的每个对象都是独立的,创建了两个对象就会有两个方法占用两个内存空间,创建了十个对象就会占用十个内存空间
原型可以让相同的方法放在同一个内存空间中,JS规定每一个构造函数都有一个prototype属性,这个属性指向的是一个对象,所以我们称其为原型对象
我们可以将方法挂载在prototype中,这样方法就会存放在相同的内存空间中
构造函数和原型中的this指向的都是实例化对象
3 在内置对象中添加方法
我们之前用的方法,比如str.split()实质上是str.prototype.split(),我们现在想在内置对象Array添加sum()方法,以便让数组中所有的数字都加起来
4 constructor 属性
每一个实例对象都有constructor属性,constructor属性指向该实例对象的构造函数
constructor是实例对象的一个属性。
构造函数也有constructor,构造函数也是被构造出来的,我们写的构造函数的constructor同样指向上一级构造函数。
原型对象(prototype)也有constructor属性,他的属性内容与实例对象的属性内容相同,都指向实例对象的构造函数
constructor属性可以帮助我们批量增加构造函数中的函数,如果我们不适用constructor,我们可以这样写
上面的写法在创造多个方法的时候会很麻烦,也可以下面这样写
上面那样写很方便,但是会丢失掉constructor属性
我们可以这样写添加construcor属性
这样就可以做到无丢失属性添加方法了
5 实例对象原型 __proto__
__proto__是实例对象的一个属性,构造函数也有__proto__,构造函数也是被构造出来的,我们写的构造函数的__proto__同样指向上一级的对象原型
在实例对象中都有一个属性__proto__指向构造函数的prototype原型对象,这个是 实例对象 可以使用 原型属性与方法的原因
- 有时候我们会看到 [[prototype]],[[prototype]]与__proto__意义相同
实例对象的__proto__与构造函数的prototype相同
__proto__只能读取不能修改
6 原型继承
我们现在有一个对象Person,然后创建一个构造函数Man,将Person赋值给Man的原型对象,然后再加一个属性
其中eays与head都是从Person中继承的属性,放在__proto__中。name是自己的属性
像上面那样写,如果你再创建一个对象,对象a与对象b,彼此不相互影响
原型继承不只有这一种方式,但大体上功能差不多
7 原型链与instanceof
7.1 原型链
原型链实际就是继承顺序,最大的是Object,Object再使用proto向上指会得到null,其余的原型对象使用proto均会得到上一级的原型对象
在使用属性的时候,代码会先找你当前级有没有这个属性,如果没有就去你的父类里找,如果都没有才会报错
7.2 instanceof
instanceof的左侧是 类a(或实例对象),右侧是 类b(不能是实例对象)。意思是 类a属不属于类b
我们再搞一个不属于的例子
下面这个是true
下面这个是false,这个我也不清楚为什么是false
下面这个是true
8 案例-模态框
这里我们使用面向对象的思想,这种思想也就是前端框架中组件的思想
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.Tip_window {
position: relative;
width:200px;
height:100px;
margin:100px auto;
border:1px solid gray;
padding:5px;
}
.Tip_header button {
position: absolute;
right:3px;
top:0px;
font-size:20px;
border:1px solid transparent;
background-color: transparent;
}
.Tip_body {
margin-top:20px;
text-align: center;
}
</style>
</head>
<body>
<button id="delete">删除</button>
<button id="login">登录</button>
</body>
<script>
function Tip_window(Tip_header_content='',Tip_body_content='') {
this.Tip_window = document.createElement('div')
this.Tip_window.className = 'Tip_window'
this.Tip_window.innerHTML = `
<div class="Tip_header">${Tip_header_content}<button>x</button></div>
<div class="Tip_body">${Tip_body_content}</div>
`
}
Tip_window.prototype.open = function() {
document.body.append(this.Tip_window)
this.Tip_window.querySelector('.Tip_header button').addEventListener('click',() => {
this.close()
})
}
Tip_window.prototype.close = function() {
this.Tip_window.remove()
}
document.querySelector('#delete').addEventListener('click',function() {
const del_Tip_window = new Tip_window('温馨提示','您没有权限删除操作')
del_Tip_window.open()
})
document.querySelector('#login').addEventListener('click',function() {
const login_Tip_window = new Tip_window('友情提示','您还没有注册')
login_Tip_window.open()
})
</script>
</html>
这里使用了箭头函数,箭头函数是this指向上一级的this,由于我们的open使用function写的,所以箭头函数的this一直往上找,找到open的this,也就是Tip_window 就停了
如果使用了function,那么this则指向函数的使用者,也就是 .Tip_header button