JS笔记(12): 对象的继承

栏目: JavaScript · 发布时间: 5年前

内容简介:原型继承:====个人认为,原型继承,call继承,寄生组合继承,class继承才是真正的继承,因为不是复制地址; 而扩展式继承和deepclone继承是把父类的地址复制地址给子类,这样当父类的属性发生改变,子类的属性也不会发生改变,所以不算是真正的继承
  • 继承:子类继承父类的属性和方法:
  • 继承的目的:就是为了代码能够更好复用,组合起来生成一个新的类别
    • 1.原型继承
    • 2.call继承
    • 3.寄生组合继承
    • 4.ES6中的class类实现继承
    • 5.扩展式继承 B.prototype = {...A.prototype}
    • 6.deepclone深克隆 B.prototype = deepclone(A.prototype)

一、原型继承

原型继承:

B.prototype = new A();

原型继承存在的问题:

  • 1.父类实例私有属性和公有属性,都变为子类实例的公有属性
  • 2.如果子类B的原型上之前有属性方法,重新执行A的实例后,之前的方法都没用了
JS笔记(12): 对象的继承
function A() {
    this.x = 100;
};
A.prototype = {
    consyructor: A,
    getX: function () {
        console.log(this.x);
    }
};
function B() {
    this.y = 200;
};
// function AA() {
//     function x() {

//     } //先创建一个空对象
//     x.prototype = B.prototype; //把父类的原型地址赋值给空对象(即空对象的原型指向父类的原型)
//     return new x;  // 返回实例
// }
B.prototype = new A; //核心 让子类的原型指向父类的实例
let f = new B();
复制代码

二、call继承(属性继承)

  • call 继承:把父类A作为普通函数执行,让A中的 this 变为B的实例,相当于给B的实例增加一个属性和方法
  • 弊端:把父类A当做普通函数执行,和原型无关了,仅仅是把A中的私有属性变为子类B实例的私有属性,A原型中的公有属性方法和B及B的实例无关
  • new A() 把A作为类创建它的实例 this:实例
  • A() 把A作为普通函数执行 this:window
function A(name) {
    // this:f 
    this.x = name; // f.x=100
};
A.prototype = {
    consyructor: A,
    getX: function () {
        console.log(this.x);//100
    }
};
function B(name) {
    // this: 实例f
    A.call(this,name); //核心 把A执行,让A中的this变为f
    this.y = name;
};
let f  = new B('abc');
console.log(f.x)
复制代码

三、寄生组合式继承

  • 子类的私有空间里继承父类的私有属性,子类的公有空间里继承父类的公有属性

  • 寄生组合式和原型继承的唯一区别:

  • B.prototype = new A(); 创建的A实例虽然指向了A的原型,但是实例中不是空的,存放了A的私有属性,这些属性变为B的公有属性

  • B.prototype = Object.create(A.prototype); 好处在于我们是创建一个没有任何私有属性的空对象,指向A的原型,这样B的公有中不会存在A四位私有属性

  • Object.create() : 内置Object类天生自带的方法,

    • 1.目的为创建一个空对象
    • 2.让新创建的空对象的__proto__指向第一个传递进来的对象(把obj作为新创建空对象的原型)
JS笔记(12): 对象的继承
// 原理:
function create(obj){
    function AA(){}
    let o = new AA;
    o.__proto__ = obj;
    return o;
}
复制代码
//关于Object.create()
let obj = {
    name: 'Tom'
};
console.log(Object.create(obj)); //{}

function A() {
    // this:f 
    this.x = 100; // f.x=100
};
A.prototype = {
    consyructor: A,
    getX: function () {
        console.log(this.x);//100
    }
};
function B() {
    A.call(this); //核心 基于call继承,把A的私有变为B的私有 f.x=100
    this.y = 200;
};
// B.prototype = A.prototype; //一般不这样处理,因为这种模式可以轻易修改父类A原型上的东西(重写),这样会导致A的其他实例受到影响
B.prototype = Object.create(A.prototype);
let f = new B();
console.log(f.x)
复制代码

四、ES6中的类继承(class继承)

  • 语法:ES6中创建类是有自己标准语法的(这种语法创建出来的类只能 new 执行,不能当做普通函数执行)
  • class继承的核心原理:
    • 1. 子类.call(this) => 继承父类的私有属性
    • 2. 子类.prototype = Object.create(父类.prototype) => 继承父类的公有方法
    • 3. 子类.__proto__ 指向父类(原本, 类.__proto__ = Function.prototype
//ES6 class继承
class A {
    constructor() {
        console.log(arguments); //Tom 子类的实例把参数传递给子类的构造函数,
        this.name = arguments;
        this.x = 100;
    }
    getX() {
        console.log(this.x);
    }
}
class B extends A{//类似与实现了原型继承
    constructor(){
        super(...arguments)
        //super类似于call继承,在这里相当于把父类的constructor执行,并且让方法中的this是B的实例,super当中传递的实参都是给A的
        this.y = 200;
        console.log(...arguments)
    }
    getY (){
        console.log(this.y);
    }
}
let f = new B('Tom','Jerry');
console.dir(f);
复制代码
//class 语法 (无继承的写法)
 class Fn { //Fn是类名,没有小括号
    constructor(n, m) {
        // super();
        //=> 等价于传统ES5中类的构造体
        this.x = n;
        this.y = m;
    }
    //=> 给Fn的原型上设置方法(只能设置方法不能设置属性)
    getX() {
        console.log(this.x);
    }
    //设置静态方法:把Fn当做一个普通对象设置的私有方法(和实例没有关系),同样也只能设置方法不能写属性
    static AA(){
        console.log(3)
    }
}
let f = new Fn(10,20);
console.log(f.x); //10
f.getX(); //10
Fn.AA(); //3
复制代码

五、 扩展式继承:(浅克隆)

B.prototype = {...A.prototype}
function A (){
    this.name = 'Tom';
};
A.prototype.getX = function(){
    console.log(this.name);
}
function B(){
    A.call(this);
    this.age = 18
}
B.prototype = {...A.prototype};
let f = new B();
console.log(f); //B {name: "Tom", age: 18} age: 18 name: "Tom" __proto__:getX:  ƒ () __proto__: Object
复制代码

六、deepclone:深克隆

function A() {
this.name = 'Tom';
};
A.prototype.getX = function () {
console.log(this.name);
}
function B() {
A.call(this);
this.age = 18
}
B.prototype = deepClone(A.prototype);
let f = new B();
console.log(f);

function deepClone(obj) {
//先声明一个数组,去存克隆出来的内容
//判断obj是否为数组,是数组就o就为[],否则为{}
let o = obj.push ? [] : {};
//循环传进来的对象
for (let attr in obj) {
    // for(let i=0;i<arr.length;i++){
    //判断对象中的某个值是否为引用类型
    //如果是,就继续调用deepClone把引用值传到函数中
    if (typeof obj[attr] === 'object') {
        o[attr] = deepClone(obj[attr])
    } else {
        //如果是简单类型就直接赋值
        o[attr] = obj[attr];
    }
}
return o;
}
复制代码

====

个人认为,原型继承,call继承,寄生组合继承,class继承才是真正的继承,因为不是复制地址; 而扩展式继承和deepclone继承是把父类的地址复制地址给子类,这样当父类的属性发生改变,子类的属性也不会发生改变,所以不算是真正的继承


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Cyberwar

Cyberwar

Kathleen Hall Jamieson / Oxford University Press / 2018-10-3 / USD 16.96

The question of how Donald Trump won the 2016 election looms over his presidency. In particular, were the 78,000 voters who gave him an Electoral College victory affected by the Russian trolls and hac......一起来看看 《Cyberwar》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具