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的实例后,之前的方法都没用了
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作为新创建空对象的原型)
// 原理: 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
)
- 1.
//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继承是把父类的地址复制地址给子类,这样当父类的属性发生改变,子类的属性也不会发生改变,所以不算是真正的继承
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- 028.Python面向对象继承(单继承,多继承,super,菱形继承)
- 面向对象:理解 Python 类的单继承与多继承
- Java继承(面向对象篇)
- 《JavaScript面向对象精要》之五:继承
- JavaScript 面向对象高级——继承模式
- 码农上工06-Java面向对象-继承
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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电子商务实战》 这本书的介绍吧!