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继承是把父类的地址复制地址给子类,这样当父类的属性发生改变,子类的属性也不会发生改变,所以不算是真正的继承


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

查看所有标签

猜你喜欢:

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

Ruby on Rails电子商务实战

Ruby on Rails电子商务实战

Christian Hellsten、Jarkko Laine / 曹维远 / 人民邮电出版社 / 2008-4 / 49.00元

《Ruby on Rails电子商务实战》全面讲解了使用Ruby on Rails创建产品级应用程序的过程。书中通过演示构建网上书店的全过程,先后介绍如何使用如TDD的敏捷实践,启动一个项目并建立良好稳定的基础,如何深入Ruby on Rails,实现诸如将应用程序翻译成各种语言对产品进行调试等的普遍需求。其中用到的主要技术包括Ajax、聚合、设置标签和国际化等,还介绍了如何使用ActiveRec......一起来看看 《Ruby on Rails电子商务实战》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试