/**
* 在es6之前没有提供extend继承,所以我们要通过 构造函数 + 原型对象 模拟实现继承,被称为 组合继承
*
* 1. call()
* 调用这个函数,可以修改函数运行的 this 指向
* fun.call(thisArg, arg1, arg2, ...);
* thisArg: 当前调用函数this的指向对象
* arg1, arg2: 传递的其他参数
*/
// 普通调用
function fn1() {
console.log(this); // 这里的this指向函数的调用者 也就是指向的是 window 对象
console.log('hello');
}
fn1(); // 调用这个函数
// call方法 call()调用函数
function fn2() {
console.log('hello ^_^');
}
fn2.call();
// call() 调用函数 并且改变函数的this的指向
function fn3(x, y) {
console.log(this,'this的指向'); // {name: "c"}
console.log(x+y)
}
var c = {
name: 'c'
}
// 改变函数fn3 的this的指向 到c这个对象中;
fn3.call(c, 1, 2); // 3
/**
* 2.借用构造函数 继承父类型的属性
* 核心原理: 通过call()把父类型的this指向到子类型的this,实现子类型继承父类型的属性
*/
// 父构造函数
function Father(name, age) {
// this 指向 父构造函数的对象实例
this.name = name;
this.age = age;
console.log(this);
/**
* Son {name: "DD", age: 19}
age: 19
name: "DD"
*/
}
// 子构造函数
function Son(name, age) {
// this 指向子构造函数的对象实例
// 子构造函数 在 调用父构造函数的属性的时候 一定要记得把父构造函数里面的this 修改为 子构造函数里面的this
// 调用了父构造函数,然后利用 call() 把父构造函数里面的this指向改为 子构造函数的this;然后就能实现子构造函数继承了父构造函数的属性
Father.call(this, name, age);
this.sex = 'men';
console.log(this);
/**
* 输出结果:
* Son {name: "DD", age: 19, sex: "men"}
age: 19
name: "DD"
sex: "men"
*/
}
var s = new Son('DD', 19);
/**
* 3.借用构造函数 继承父类型的方法
* 利用原型指向
*/
// 父构造函数
function F(name, age) {
this.name = name;
this.age = age;
}
F.prototype.sing = function() {
console.log('唱歌')
}
// 子构造函数
function S(name, age) {
F.call(this, name, age);
}
/**
* 继承父构造函数的方法 的错误写法
* 直接将子构造函数的原型对象prototype 指向 父构造函数的原型对象
S.prototype = F.prototype;
*
* 错误:
* 父构造函数 F =====> F构造函数原型对象 (F.prototype)
* 子构造函数 S =====> S构造函数原型对象 (S.prototype)
* 我们把父构造函数里面的原型对象,给了子构造函数里面的原型对象
* 相当于把子构造函数原型对象 指向了 父构造函数的原型对象 (地址赋值了)
* 然后子构造函数发生了变化 父构造函数也会发生变化
*/
// 正确写法
/**
* new F()
* 创建了一个Fr的实例对象(与F的原型对象不是同一个对象)
* S.prototype = new F()
* 让 S 的原型对象 指向了 F 的实例对象(因为F的实例对象有个__proto__原型根据原型链 去访问F 的原型对象)
* F实例对象 和 F的原型对象 地址是不一样的
*/
S.prototype = new F();
S.prototype.dance = function() {
console.log('跳舞')
}
var ss = new S('柒柒', 3);
console.log(ss)