当前位置: 首页/ 学苑/学习Note/

继承

2018-05-10| 阅读:641 |类别:学习Note

一、继承的基本概念   

相对于 JavaScript 来说,在其他一些面向对象的编程语言中,继承主要指的是父类和子类的一些关系。

而在 JavaScript 中,继承主要是基于原型链来实现的。更简单地说,在 JavaScript 中,某个对象可以访问到另一个对象中的属性和方法,我们就可以认为它们之间存在继承关系

function Fruit() {
    // code...
}

var apple = new Fruit();

apple.__proto__ === Fruit.prototype;

实例 apple 不仅可以访问到自身的属性和方法,同时也可以访问到 Fruit.prototype 中的属性和方法,所以我们说 apple 继承自 Fruit.prototype 。

二、 JavaScript 中主流的继承方式

1、基于原型链实现继承

原型对象就是某个构造函数的 prototype 属性所指向的那个对象,也就是构造函数的实例的 __proto__ 属性所指向的那个对象。而原型对象上其实也有一个 __proto__ 属性指向另外一个对象。

已知一个对象,通过这个对象上的__proto__属性找到构造函数的原型对象,再通过原型对象上的__proto__属性找到这个原型的构造函数的原型,最终找到某个不含有__proto__属性的对象终止(原型链的顶端)的链式结构,我们称之为原型链。

(1) 扩展原型对象
function Person() {}

var p1 = new Person();

当一个函数创建好之后,就会有一个默认的原型对象。在给这个原型对象添加属性和方法时,就用到了扩展原型对象实现继承

Person.prototype.run = function() {
    console.log("I'm running");
};

console.log(p1.run);

此时,p1 是可以访问到 run 方法的,我们就说 p1 继承自 Person.prototype 。

(2) 替换原型对象
function Person() {}

// 替换原型对象
Person.prototype = {
    constructor: Person,  // 重点
    run: function() {},
    say: function() {},
    sing: function() {},
    walk: function() {}
};

// 实例可以访问
var p1 = new Person();
p1.run;
p1.say;

function Person() {}

Person.prototype.run = function() {
    // code...
};

var p1 = new Person();   // p1.__proto__ 指向默认的原型对象

Person.prototype = {
    constructor: Person,
    say: function() {
        // code...
    }
};

var p2 = new Person();   // p2.__proto__ 指向新的原型对象

console.log(typeof p1.say); // undefined
console.log(typeof p2.say); // "function"

2. 混入继承(又称拷贝继承)

由于参数非常多,我们在传递参数时就必须非常小心,一旦传错,整个信息就会错乱。于是我们找到了一个很好的解决办法,可以把这些参数当成一个对象来传递。

function getAddress(obj) {
    for (var key in obj) { // key 保存了 obj 中每一个属性的属性名
        // 获取指定属性的值
        this[key] = obj[key]; // this["street"] = obj["street"]
    }
}

getAddress({
    street: 'xxx',
    country: 'China',
    name: 'zs',
    city: 'Beijing',
    code: '102611',
    tel: '13888889999',
    province: 'Beijing',
});

function mixin(target, source) {
    for (var key in source) {
        target[key] = source[key];
    }
    
    return target;
}

var obj1 = { name: 'zs', age: 18 };
var obj2 = {};

mixin(obj2, obj1);

简单来说,就是利用 for…in 循环,将源对象中的属性和方法拷贝到目标对象中,从而实现继承。

3. 原型式继承(也叫经典继承)

有时候,我们仅仅想继承自身没有的属性,而保留自身已有的属性。这个时候,混入继承是做不到了,但原型式继承却可以。

var obj3 = { name:'ls', age: 18 };

function F() {}

F.prototype = obj3;  // 让 F 的实例可以访问到 obj3 的属性和方法

var obj4 = new F();

obj4.name = 'ww';

obj4.gender = '女';

console.log(obj4.name);  // obj4 有自己的 name,打印 'ww'

console.log(obj4.gender); // obj4 有自己的 gender,打印 '女'

console.log(obj4.age);  // obj4 没有自己的 age,访问 obj3 中的 age,打印 18

参考:https://juejin.im/post/5af31165f265da0b912770fc

觉得有用,烦请给个小赏¥以资鼓励!~~