继承
- 继承是和构造函数相关的一个应用
- 是指,让一个构造函数去继承另一个构造函数的属性和方法
- 所以继承一定出现在 两个构造函数之间
原型继承
// 父类构造函数
function Father(name, age){
this.name = name
this.age = age
}
Father.prototype.money = function(){
console.log('一个小目标!')
}
// 子类构造函数
function Son(name, age){
this.name = name
this.age = age
}
// 怎么让子类构造函数去继承父类构造函数的方法呢?
Son.prototype = Father.prototype
// 例如:你给子类构造函数的原型上面添加一个方法
Son.prototype.love = function(){
console.log('喜欢谈👫🏻!')
}
let s = new Son('赵三', 20)
s.money()
s.love()
let f = new Father('赵俊骏', 50)
f.love()
console.log(Father.prototype)
console.log(Son.prototype)
关键代码:
Son.prototype = Father.prototype
以上方法不太好,直接覆盖了原来的原型对象
// 推荐使用的方式,把父类的实例化对象给子类的原型对象
Son.prototype = new Father('赵三', 20)
// 例如:你给子类构造函数的原型上面添加一个方法
Son.prototype.love = function(){
console.log(this.name + '喜欢谈👫🏻!')
}
let s = new Son()
s.love()
s.money()
s.rg()
console.log(Son.prototype)
// let f = new Father('赵俊骏', 50)
// f.love() // f.love is not a function
把父类的实例化对象给子类的原型对象
原型继承,就是在本身的原型链上加一层结构
关键代码:Son.prototype = new Father('赵三', 20)
- 原型继承优缺点:
优点:构造函数体内和原型上的都可以继承
缺点:
一个构造函数的内容,在两个位置传递参数
继承来的属性不再子类实例的身上
借用构造函数继承
把父类构造函数体借用过来使用一下而已
// 父类构造函数
// 第四步:在进入函数体内之前,先进行形参赋值 name='张三' age=18
function Father(name, age){
// 第五步:改变了this执行,之前的this指向的是window,现在指向的是Son构造函数的实例化对象
// 例如:new Son().name = name
// 第五步:进行赋值操作
this.name = name
this.age = age
// 注意点:构造函数也可以当成普通函数去调用,也可以实例化调用
// console.log(this)
}
Father.prototype.money = function(){
console.log('一个小目标')
}
// 子类构造函数
// call() 改变函数内部的this指向,传递参数就是正常的传递(你给函数怎么传递参数的就怎么传参)
// 第二步:在进入函数体内之前,先进行形参赋值 name='张三' age=18 sex='男'
function Son(name, age, sex){
// 第三步:执行Father.call(this, name, age)这个函数,call函数会立即调用,实际上去调用Father函数,在调用之前先传递实参 '张三', 18
Father.call(this, name, age)
this.sex = sex
}
// 第一步:当实例化对象的时候,调用函数并传递实参进去 '张三', 18, '男'
const s = new Son('张三', 18, '男')
console.log(s)
关键代码:Father.call(this, name, age)
-
借用构造函数继承优缺点:
优点:
继承来的属性是在自己身上
我们一个实例化过程在一个位置传递参数
缺点:
只能继承父类构造函数体内的内容
父类原型上的内容不能继承
组合继承
- 就是把
原型继承和借用构造函数继承两个方式组合在一起
// 父类构造函数
function Father(name, age){
this.name = name
this.age = age
}
Father.prototype.money = function(){
console.log('一个小目标')
}
// 子类构造函数
function Son(name, age, sex){
Father.call(this, name, age)
this.sex = sex
}
Son.prototype = new Father()
Son.prototype.say = function(){
console.log('喜欢说话!')
}
const s = new Son('张三', 18, '男')
console.log(s)
s.money()
s.say()
关键代码:
function Son() {
Person.call(this)
}
Student.prototype = new Father()
-
组合继承的优缺点:
优点:
父类构造函数体内和原型上的内容都能继承
继承下来的属性放在自己身上
在一个位置传递所有的参数
缺点:
当你给子类添加方法的时候,实际上是添加在父类的实例身上
ES6的继承
直接把继承方案变成了extends关键字了,直接使用即可
注意点: ES6的基础方案其实内部的实现依旧是组合继承
class Father{
constructor(name, age){
this.name = name
this.age = age
}
money(){
console.log('一个小目标')
}
}
class Son extends Father{
constructor(name, age, sex){
// 注意点:super() 超级函数必须先调用,再去定义子类的属性
super(name, age)
this.sex = sex
}
}
const s = new Son('王成', 18, '男')
console.log(s)
s.money()
关键代码:
// 下面表示创造一个 Son 类,继承自 Father 类
class Son extends Father {
constructor () {
// 必须在 constructor 里面执行一下 super() 完成继承
super()
}
}
拷贝继承
const obj = {
name: '张三',
age: 18,
say(){
console.log('hello')
}
}
const data = {}
for(let key in obj){
data[key] = obj[key]
}
console.log(data)
data.say()
继承案例
- 第一个div拖拽
- 第二个div在拖拽的时候需要限定它拖拽的范围
*{
margin: 0;
padding: 0;
}
html, body{
height: 100%;
}
div{
width: 200px;
height: 200px;
position: absolute;
}
.box1{
background-color: hotpink;
}
.box2{
background-color: orange;
}
<body>
<div class="box1"></div>
<div class="box2"></div>
<script>
// 获取元素
// const box2 = document.querySelector('.box2')
// 实现拖拽效果
class Drag{
constructor(ele){
this.box = document.querySelector(ele)
this.init()
}
init(){
this.down()
this.up()
}
down(){
this.box.onmousedown = (e)=>{
let l = e.offsetX
let t = e.offsetY
this.move(l, t)
}
}
move(l, t){
document.onmousemove = (e)=>{
let x = e.clientX - l
let y = e.clientY - t
this.box.style.left = x + 'px'
this.box.style.top = y + 'px'
}
}
up(){
document.onmouseup = ()=>{
document.onmousemove = null
}
}
}
new Drag('.box1')
// 需求:第二个div在拖拽的时候需要限定它拖拽的范围
// 注意点:有继承后可以定制化开发一些东西,并且可以减少代码量,优化性能
class Drag2 extends Drag{
constructor(ele){
super(ele)
}
// 重新move()方法
move(l, t){
document.onmousemove = (e)=>{
let x = e.clientX - l
let y = e.clientY - t
// 范围限定
if(x<=0){
x = 0
}else if(x>=window.innerWidth - this.box.offsetWidth){
x = window.innerWidth - this.box.offsetWidth
}
if(y<=0){
y = 0
}else if(y>=window.innerHeight - this.box.offsetHeight){
y = window.innerHeight - this.box.offsetHeight
}
this.box.style.left = x + 'px'
this.box.style.top = y + 'px'
}
}
}
new Drag2('.box2')
</script>
</body>