一、继承父类方法
ES6之前并没有给我们提供extends继承,所以我们可以通过构造函数+原型对象模拟实现继承,被称为组合继承。
call()
调用这个函数,并且修改函数运行时的this指向 基本格式为:fun.call(thisArg,arg1,arg2,...)
thisArg:当前调用函数this的指向对象
arg1,arg2…:传递的其他参数
call有两个作用:
1、call可以调用函数
<!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>
</head>
<body>
<script>
function fn(){
console.log('haha');
}
fn.call();//结果为haha
</script>
</body>
</html>
2、修改函数里的this指向
<!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>
</head>
<body>
<script>
//在未改变前,函数里的this指向window,现在可以使用call让函数里的this指向我们创建的对象obj
function fn(x,y){
console.log(this);
console.log(x,y);
}
var obj = {
name:'haha'
}
fn.call(obj,1,2);
</script>
</body>
</html>
结果为:
1、借助构造函数继承父类型属性
通过call()把父类的this指向子类型的this,这样就可以实现子类型继承父类型的属性。
<!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>
</head>
<body>
<script>
//父构造函数
function Father(uname,age){
//this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
//子构造函数
function Son(uname,age,sex){
//this指向子构造函数的对象实例
//改变this指向
Father.call(this,uname,age);
this.sex = sex;
}
var son = new Son('haha',12,'女');
console.log(son);
</script>
</body>
</html>
2、借助构造函数继承父类型方法
(1)直接使父构造函数的原型对象等于子构造函数的原型对象
<!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>
</head>
<body>
<script>
//父构造函数
function Father(uname,age){
//this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function(){
console.log('今日赚200元');
}
//子构造函数
function Son(uname,age,sex){
//this指向子构造函数的对象实例
//改变this指向
this.sex = sex;
Father.call(this,uname,age);
}
Son.prototype = Father.prototype;
var son = new Son('haha',12,'女');
console.log(son);
son.money();
</script>
</body>
</html>
可以看出,此时的子构造函数对象实例中包括了父构造函数原型对象的money方法,而且可以调用money方法。
但是这种方法有一个缺点,我们可以给Son的原型对象增加一个方法,然后打印出父构造函数的原型对象看一看。
<!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>
</head>
<body>
<script>
//父构造函数
function Father(uname,age){
//this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function(){
console.log('今日赚200元');
}
//子构造函数
function Son(uname,age,sex){
//this指向子构造函数的对象实例
//改变this指向
this.sex = sex;
Father.call(this,uname,age);
}
Son.prototype = Father.prototype;
var son = new Son('haha',12,'女');
Son.prototype.say = function(){
console.log('hello');
}
console.log(Father.prototype);
</script>
</body>
</html>
此时,我们会发现父构造函数的原型对象也包括了子构造函数原型对象中的say方法,这是因为我们在执行Son.prototype = Father.prototype;时,使Son的原型对象引用指向了父构造函数的原型对象,所以覆盖了Father.prototype,所以我们改变Son.prototype,Father.prototype也随之改变了。
(2)利用原型对象实现方法的继承
我们可以让子原型对象成为父构造函数的实例对象,这样子原型对象可以通过__proto__继承到父原型对象里的方法,且因为实例对象与原型对象的地址是不同的,所以给子原型对象增加方法时,也不会覆盖父原型对象。但是注意,要利用constructor将Son指回原来的构造函数。
代码示例为:
<!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>
</head>
<body>
<script>
//父构造函数
function Father(uname,age){
//this指向父构造函数的对象实例
this.uname = uname;
this.age = age;
}
Father.prototype.money = function(){
console.log('今日赚200元');
}
//子构造函数
function Son(uname,age,sex){
//this指向子构造函数的对象实例
//改变this指向
this.sex = sex;
Father.call(this,uname,age);
}
//子构造函数专门的方法
Son.prototype = new Father();
//如果利用对象的形式修改了原型对象,别忘了利用constructor指回原来的构造函数
Son.prototype.constructor = Son;
var son = new Son('haha',12,'女');
Son.prototype.say = function(){
console.log('hello');
}
console.log(son);
console.log(Son.prototype);
console.log(Father.prototype);
</script>
</body>
</html>
图解如下: