继承
JS中继承的概念:
- 通过【某种方式】让一个对象可以访问到另一个对象中的属性和方法,我们把这种方式称之为继承
并不是所谓的xxx extends yyy
为什么要使用继承?
- 有些对象会有方法(动作、行为),而这些方法都是函数,如果把这些方法和函数都放在构造函数中声明就会导致内存的浪费
function Person(){ this.say=function(){ console.log("你好") } } var p1=new Person(); var p2=new Person(); console.log(p1.say === p2.say); //false
继承的第一种方式:原型链继承1
Person.prototype.say=function(){ console.log("你好") }
- 缺点:添加1、2个方法无所谓,但是如果方法很多会导致过多的代码冗余
继承的第二种方式:原型链继承2
Person.prototype = { //切记不能忘记 constructor:Person, say:function(){ console.log("你好"); }, run:function(){ console.log("正在进行百米冲刺"); } }
- 注意点:
- a、一般情况下,应该先改变原型对象,再创建对象
- b、一般情况下,对于新原型,会添加一个constructor属性,从而不破坏原有的原型对象的结构
继承的第三种方式:拷贝继承(混入继承:mixin)
- 场景:有时候想使用某个对象中的属性,但是又不能直接修改它,于是就可以创建一个该对象的拷贝
- 实际运用:
- jquery:$.extend:编写jquery插件的必经之路
- 基于jquery封装一个表格控件
- jquery:$.extend:编写jquery插件的必经之路
var o1={ age:2 }; var o2 = o1; o2.age=18; //1、修改了o2对象的age属性 //2、由于o2对象跟o1对象是同一个对象 //3、所以此时o1对象的age属性也被修改了
var o3={gender:"男",grade:"初三",group:"第五组",name:"张三"}; var o4={gender:"男",grade:"初三",group:"第五组",name:"李四"}; //上述代码中,如果使用拷贝继承对代码进行优化会非常和谐 //实现拷贝继承: //1、已经拥有了o3对象 //2、创建一个o3对象的拷贝(克隆):for...in循环 //3、修改克隆对象,把该对象的name属性改为"李四"
- 实现1:
var source={name:"李白",age:15} var target={}; target.name=source.name target.age=source.age;
- 浅拷贝和深拷贝
- 浅拷贝只是拷贝一层属性,没有内部对象
- 深拷贝其实是利用了递归的原理,将对象的若干层属性拷贝出来
var students=[ {name:"",age:""}, {name:"",age:""} ]
- 上面的方式很明显无法重用,实际代码编写过程中,很多时候都会使用拷贝继承的方式,所以为了重用,可以编写一个函数把他们封装起来:
function extend(target,source){ for(key in source){ target[key]=source[key]; } return target; } extend(target,source)
- 由于拷贝继承在实际开发中使用场景非常多,所以很多库都对此有了实现
- jquery:$.extend
- es6中有了 仿佛就是专门为了拷贝继承而生:
- 优点:简单的令人发指
var source={name:"李白",age:15} //让target是一个新对象,同时拥有了name、age属性 var target={ ...source } var target2={ ...source,age:18 }
继承的第四种方式:原型式继承:(道格拉斯在蝴蝶书中提出来的)
- 场景:
- a、创建一个纯洁的对象:对象什么属性都没有
- b、创建一个继承自某个父对象的子对象
js var parent={ age:18,gender:"男"}; var student=Object.create(parent); //student.__proto__===parent
- 使用方式:
- 空对象:Object.create(null)
var o1={ say:function(){} } var o2=Object.create(o1);
继承的第五种方式:借用构造函数实现继承
- 场景:适用于2种构造函数之间逻辑有相似的情况
- 原理:函数的call、apply调用方式
function Animal(name,age,gender){ this.name=name; this.age=age; this.gender=gender; } function Person(name,age,gender,say){ this.name=name; this.age=age; this.gender=gender; this.say=function(){ } }
局限性:Animal(父类构造函数)的代码必须完全适用于Person(子类构造函数)
- 以上代码用借用构造函数实现
function Animal(name,age){ this.name=name; this.age=age; } function Person(name,age,address){ Animal.call(this,name); //this.name=name; //this.age=age; this.address=address; }
- 寄生继承、寄生组合继承...
来源:https://www.cnblogs.com/guojbing/p/10405862.html