JS 虽然不像是 JAVA 那种强类型的语言, 但也有着与 JAVA 类型的继承属性, 那么 JS 中的继承是如何实现的呢?
一, 构造函数继承
在构造函数中, 同样属于两个新创建的函数, 也是不相等的
- function Fn(name){
- this.name = name;
- this.show = function(){
- alert(this.name);
- }
- }
- var obj1 = new Fn("AAA");
- var obj2 = new Fn("BBB");
- console.log(obj1.show==obj2.show); //false
此时可以看出构造函数的多次创建会产生多个相同函数, 造成冗余太多.
利用原型 prototype 解决. 首先观察 prototype 是什么东西
- function Fn(){}
- console.log(Fn.prototype);
- //constructor 表示当前的函数属于谁
- //__proto__ == [[prototype]], 书面用语, 表示原型指针
- var fn1 = new Fn();
- var fn2 = new Fn();
- Fn.prototype.show = function(){
- alert(1);
- }
- console.log(fn1.show==fn2.show); //ture
此时, 任何一个对象的原型上都有了 show 方法, 由此得出, 构造函数 Fn.prototype 身上的添加的方法, 相当于添加到了所有的 Fn 身上.
二, call 和 applay 继承
- function Father(skill){
- this.skill = skill;
- this.show = function(){
- alert("我会"+this.skill);
- }
- }
- var father = new Father("绝世木匠");
- function Son(abc){
- // 这里的 this 指向函数 Son 的实例化对象
- // 将 Father 里面的 this 改变成指向 Son 的实例化对象, 当相遇将 father 里面所有的属性和方法都复制到了 son 身上
- //Father.call(this,abc);// 继承结束, call 适合固定参数的继承
- //Father.apply(this,arguments);// 继承结束, apply 适合不定参数的继承
- }
- father.show()
- var son = new Son("一般木匠");
- son.show();
三, 原型链继承 (demo)
这个的么实现一个一个简单的拖拽, a->b 的一个继承. 把 a 的功能继承给 b.
- html:
- 1 <div id="drag1"></div>
- 2 <div id="drag2"></div>
- CSS:
- 1 *{margin: 0;padding: 0;}
- 2 #drag1{width: 100px;height: 100px;background: red;position: absolute;}
- 3 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}
- JS:
- function Drag(){}
- Drag.prototype={
- constructor:Drag,
- init:function(id){
- this.ele=document.getElementById(id);
- this.cliW=document.documentElement.clientWidth||document.body.clientWidth;
- this.cliH=document.documentElement.clientHeight||document.body.clientHeight;
- var that=this;
- this.ele.onmousedown=function(e){
- var e=event||window.event;
- that.disX=e.offsetX;
- that.disY=e.offsetY;
- document.onmousemove=function(e){
- var e=event||window.event;
- that.move(e);
- }
- that.ele.onmouseup=function(){
- document.onmousemove=null;
- }
- }
- },
- move:function(e){
- this.x=e.clientX-this.disX;
- this.y=e.clientY-this.disY;
- this.x=this.x<0?this.x=0:this.x;
- this.y=this.y<0?this.y=0:this.y;
- this.x=this.x>this.cliW-this.ele.offsetWidth?this.x=this.cliW-this.ele.offsetWidth:this.x;
- this.y=this.y>this.cliH-this.ele.offsetHeight?this.y=this.cliH-this.ele.offsetHeight:this.y;
- this.ele.style.left=this.x+'px';
- this.ele.style.top=this.y+'px';
- }
- }
- new Drag().init('drag1')
- function ChidrenDrag(){}
- ChidrenDrag.prototype=new Drag()
- new ChidrenDrag().init('drag2')
四, 混合继承
- function Father(skill,id){
- this.skill = skill;
- this.id = id;
- }
- Father.prototype.show = function(){
- alert("我是 father, 这是我的技能"+this.skill);
- }
- function Son(){
- Father.apply(this,arguments);
- }
- // 如果不做 son 的原型即成 father 的原型, 此时会报错: son.show is not a function
- Son.prototype = Father.prototype;
- // 因为, 如果不让 son 的原型等于 father 的原型, son 使用 apply 是继承不到原型上的方法
- // 但这是一种错误的原型继承示例, 如果使用这种方式, 会导致修改 son 原型上的 show 方法时, 会把 father 身上的 show 也修改
- // 内存的堆和栈机制
- Son.prototype.show = function(){
- alert("我是 son, 这是我的技能"+this.skill);
- }
- var father = new Father("专家级铁匠","father");
- var son = new Son("熟练级铁匠","son");
- father.show();
- son.show();
上面的示例应该修改成以下形式:
以上红色的代码应改成:
- for(var i in Father.prototype){
- Son.prototype[i] = Father.prototype[i];
- }
- // 遍历 father 的原型身上的所有方法, 依次拷贝给 son 的原型, 这种方式称为深拷贝
这种继承方式叫做混合继承, 用到了 for-in 继承, cell 和 apple 继承.
五, Es6 的 class 继承 (demo)
这个 demo 的功能和原型链继承的 demo 功能一样, a->b 的继承
- HTML:
- 1 <div id="drag1"></div>
- 2 <div id="drag2"></div>
- CSS:
- 1 *{margin: 0;padding: 0;}
- 2 #drag1{width: 100px;height: 100px;background: red;position: absolute;}
- 3 #drag2{width: 100px;height: 100px;background: black;position: absolute;left: 500px;}
- JS:
- class Drag{
- constructor(id){
- this.ele=document.getElementById(id);
- this.init();
- };
- init(){
- var that=this;
- this.ele.onmousedown=function(e){
- var e=event||window.event;
- that.disX=e.offsetX;
- that.disY=e.offsetY;
- document.onmousemove=function(e){
- var e=event||window.event;
- that.move(e);
- }
- that.ele.onmouseup=function(){
- document.onmousemove=null;
- that.ele.onmouseup=null;
- }
- }
- };
- move(e){
- this.ele.style.left=e.clientX-this.disX+"px";
- this.ele.style.top=e.clientY-this.disY+"px";
- }
- }
- new Drag("drag1");
- class ExtendsDrag extends Drag{
- constructor(id){
- super(id);
- }
- }
- new ExtendsDrag("drag2")
我总结的这几种继承方法. 两个 demo 继承的方法大家最好在编译器上跑一下, 看看. 这样才能更深刻的去理解. 尤其是原型链的继承, js 作为一个面向对象的编程语言, 还是很常用的.
来源: https://www.cnblogs.com/alongup/p/9271397.html