js 的原型链 以及伪继承
来源:互联网 发布:知乎注册要钱吗 编辑:程序博客网 时间:2024/06/10 05:46
代码都用关包的方式来显示(function(){//....code.....})();这是一个良好的习惯
1.名词解释
(function(){ function A(){ this.createId2=function(){ this.id2=2; } } A.prototype.id=1;//通过静态方式创建静态成员 A.prototype.createId3=function(){ this.id3=3; } var a=new A(); a.createId2();//通过调用动态成员函数创建 动态成员 a.createId3();//通过静态函数创建 动态成员 a.id4=4;//直接创建动态成员})()
1.1构造函数:
在new 的时候被执行的函数;如:整个A就是一个构造函数
1.2 动态成员:
在new 之后创建的成员,包括构造函数中创建的,元素new之后赋值通过函数 如构造器中的var id0=0,this.id=5,执行a.createId4()时创建的id4,以及直接赋值创建的:a.id3=7;
1.3 静态成员:
使用prototype方式声明的成员,如 A.prototype.id_2=1;也就是保存在prototype中的成员
2.动态成员,静态成员的特性
2.1 删除成员
(function(){ funciton A(){ this.id=1;//创建一个动态id成员 delete this.id//删除动态成员 } A.prototype.id_2=1;//创建一个静态成员 delete A.prototype.id_2;//删除一个静态成员})();
2.2 访问成员
2.2.1 优先级 动态成员>静态成员
(function(){ function A(){ console.log(this.id);//访问到静态成员 //--->2 this.id=1; console.log(this.id);//访问到动态成员 delete this.id; console.log(this.id);//动态属性被删除,则访问到静态成员 //-->2 } A.prototype.id=2; var a=new A(); a.id=1; console.log(a.id);//获取到的是动态成员 //--->1 delete a.id;//删除动态属性id console.log(a.id);//因为动态成员被删除 获取到的是静态成员 //--->2 delete a.id;//删除动态属性id,因为a.id已经被删除了所以这个操作无效 console.log(a.id); //--->1 delete A.prototype.id;删除静态成员id console.log(a.id); //--->undefined;})();
2.2.2 外部创建
(function(){ function A(){ this.createId2=function(){ this.id2=2; } } A.prototype.id=1;//通过静态方式创建静态成员 A.prototype.createId3=function(){ this.id3=3; } var a=new A(); a.createId2();//通过调用动态成员函数创建 动态成员 a.createId3();//通过静态函数创建 动态成员 a.id4=4;//直接创建动态成员})()
一个有趣的例子
(function(){ function A(){ this.say=function(){ console.log(this.id); } } var a=new A(); a.say();//调用动态成员方法 //--->undefined //因为没有名为id成员 a.id=1;//外部创建动态成员 a.say(); //--->1;})();
2.2.3 共享性
例子1:
(function(){ function A(){ this.func1=function(){}; } A.prototype.func2=function(){}; console.log(new A().func1===new A().func1);//动态成员 func1之间的比较 //--->false console.log(new A().func2===new A().func2);//静态成员 func2之间的比较 //--->true})();
例子2
(function(){ function A(){ this.id=1; } A.prototype.id2=2; var a=new A(); var b=new A(); a.id=7; console.log(b.id);//因为id是动态成员所b不受应影响 //-->2 console.log(a.id2);//公共属性 //-->2 a.id2=3; ////创建了一个动态属性id2 console.log(b.id2);//因为a.id2为动态的所以无法影响到b //-->2 A.prototype.id2=777; delete a.id2;//删除动态成员a.id2 console.log(a.id2);//获取a.静态成员 id2 //--->7 console.log(b.id2);//获取b.静态成员 id2 //--->7})();
总结:
1.动态成员,实例化对象之间完全独立2.静态成员,实例化对象之间完全共享
3.原型链继承说明
3.1 new关键字
例子(function(){ function A(){ console.log(this.id); } A.prototype.id=1; A();//没有使用new 是无法访问到静态成员的 //-->undefined; new A(); //-->1;})();在使用new关键字的时候,先找到A的原型链,也就是A.prototype并吧这个链的引用复制给构造函数 构造函数中也就可以调用到静态成员了
3.2 原型链继承的实质
3.2.1 继承,重写的实质
使用 new 关键字产生一个静态成员的引用集合,在构造函数以及之后的行为中创建动态成员,如果动态成员的名字和静态成员的名字相同,因为访问优先级的问题,this关键字就只能调用到动态成员了,这就实现了类似重写的功能
3.2.2在重写了成员以后,如何调用原来的成员
在java中,可以使用this.super关键字调用到父类的成员,同样 在js中则使用 [函数名].prototype.[成员名] 来调用父类成员
(function(){ function A(){ this.id=0; console.log(this.id); //-->0 console.log(A.prototype.id); //-->1 } A.prototype.id=1; new A();})();
4.伪继承:曲线救国
4.1 静态继承
4.1.1 基本方法
(function(){ function A(){ this.id=1; } A.prototype.id2=2; function B(){} B.prototype=new A();///B继承A console.log(B.prototype.id); //-->1 console.log(B.prototype.id2); //-->2})();
这个代码的目的是让B继承A的成员,
方法就是:B.prototype=new A();
4.1.2 继承特性
把所有的父类成员,不管是动态还是静态,都转化为子类的静态成员
4.1.3 私有变量的继承关系
(function(){ function A(){ var _id=0; this.setId=function(id){ _id=id; } this.getId=function(){ return _id; } } function B(){} B.prototype=new A(); new B().setId(1000); console.log(new B().getId()); //--->1000})();私有成员也是可以被继承的!!!!!!!! 只不过子类无法访问,但确实存在!!!!!!!!!!
4.1.4 继承原理
4.1.4.1 prototype赋值的方式原理
(function(){ function B(){} B.prototype={id:1};//初始化B的原型链上的成员 B.prototype.name='oyb'; console.log(B.prototype.id); //--->1 console.log(new B().id); //--->1 console.log(new B().name); //-->oyb})();
4.1.4.1 静态继承的实质
(function(){ function A(){ this.id=1; } A.prototype.id2=2; function B(){} var a=new A(); console.log(a); //-->A {id: 1, id2: 2} B.prototype=a;///初始话B的静态成员 console.log(B.prototype.id); //-->1 console.log(B.prototype.id2); //-->2})();
如果A的构造方法带有参数 就B.prototype=new A(arg1,arg2,arg3);//把参数带进去就可以了
4.1.3 私有变量的继承关系
(function(){ function A(){ var _id=0; this.setId=function(id){ _id=id; } this.getId=function(){ return _id; } } function B(){} B.prototype=new A(); new B().setId(1000); console.log(new B().getId()); //--->1000})();
私有成员也是可以被继承的!!!!!!!! 只不过子类无法访问,但确实存在!!!!!!!!!!
4.2 动态继承
4.1.1 基本方法
(function(){ function A(){ this.id=1; } function B(){ A.call(this);//动态继承的代码 } var b=new B(); console.log(b.id); //-->1})();核心方法 [父类].call(this);
如果父类有构造函数的话 就 ["父类"].call(this,arg1,arg2,arg3);4.1.2 特性
(function(){ function A(){ this.id=1; } A.prototype.id2=2; function B(){ A.call(this); } console.log(B.prototype.id); //-->undefined console.log(B.prototype.id2); //-->undefined var b=new B(); console.log(b.id); //-->1 console.log(b.id2); //undefined})();只能继承动态成员,并且继承之后的成员仍旧是动态的!!!!!! 这样就可以避免属性重复问题4.1.2 原理
使用了js的反射,实质上就是把A当作一个函数在B的构造函数中运行了一遍4
4.1.3私有属性的继承
和静态继承相似,一样会被继承下来,外部不能访问,但是是作为动态成员继承下来,所以不会被共享
4.3 混合式继承
因为静态继承,所有成员都是互相共享,方法适合用静态继承,属性因为是独立的所以适合用动态继承方式,或者干脆不继承,直接在子函数中创建一个(function(){ function A(){ this.id=1; } A.prototype.setId=function(id){ this.id=id; } A.prototype.getId=function(){ return this.id; } function B(){ A.call(this);//动态继承属性 } B.prototype=new A();//静态集成方法 var b=new B(),c=new B(); b.setId(1010101); console.log(c.getId()); //-->1})()(function(){ function A(){} A.prototype.setId=function(id){ this.id=id; } A.prototype.getId=function(){ return this.id; } function B(){ this.id=1; } B.prototype=new A();//静态集成方法 var b=new B(),c=new B(); b.setId(1010101); console.log(c.getId()); //-->1})()5 引入工厂模式
无论是使用静态还是动态的声明方式 那就是静态方法只能访问无法访问动态的私有变量,如上一个例子, var b=new B();b.id 是完全暴露出来的,外部可以随意修改id属性,如果想要封装怎么办?使用工厂模式的话可以很好的解决这个问题
(function(){ var factory=new function(){ function A(){} A.prototype.setId=function(id){ this.id=id; } A.prototype.getId=function(){ return this.id; } function B(){} B.prototype=new A(); B.prototype.say=function(){ console.log("say:"+this.getId()); } function C(){ this.id=null; this.getId=function(){ return this.id+"这个方法被覆盖了" ; } this.getId2=function(){ return C.prototype.getId.call(this)+":调用原来的方法"; } } C.prototype=new A(); return { getB:function(id){ var obj=new B(); obj.id=id; return { getId:function(){ return obj.getId(); }, setId:function(id){ obj.setId(id); }, say:function(){ obj.say(); } } }, getC:function(){ var obj=new C(); return { getId:function(){ return obj.getId(); }, setId:function (id){ obj.setId(id); }, getId2:function(){ return obj.getId2() } } } }};var b=factory.getB(12);b.say();//-->say:12b.setId(1111);b.say();//-->say:1111var c=factory.getC();c.setId(988101);console.log(c.getId());//-->988101这个方法被覆盖了console.log(c.getId2());//-->988101:调用原来的方法})();
工厂模式的好处是 把接口都放在了工厂里,类的外部接口, 以及构造函数都表现在了工厂里比较容易管理
如果使用工厂模式 最好使用 seajs 或者requirejs 对整个把代码模块化,不然代码膨胀速度将会不可控制
- js 的原型链 以及伪继承
- JS:原型、原型链、继承
- 原型链以及继承
- js的原型继承
- js的原型继承
- 【JS】原型链继承
- js原型链继承
- javascript中的继承(JS基于原型链的继承),以及JS中的call和apply函数
- 对于js原型和原型链继承的简单理解(第一种,原型链继承)
- 理解JS原型以及实现继承
- js真正的原型继承
- js继承,各种继承的优缺点(原型链继承,组合继承,寄生组合继承)
- Js中的原型继承和原型链
- Js关于原型以及原型链的详细介绍
- js原型链与继承
- JS继承及原型链
- js原型链及继承
- JS继承与原型链
- python中单引号,双引号和三个双引号的区别
- poj 2127(最长公共上升子序列)
- vb打开FoxPro的DBF文件的例子
- iOS 遍历类成员
- 开发笔记之20140218
- js 的原型链 以及伪继承
- 拓胜六十二、六十三天(周末)
- iphone使用keychain来存取用户名和密码
- Java transient关键字
- tomcat内存溢出总结
- 设备驱动(六)
- POJ 3641 Pseudoprime numbers 测试费马小定理伪素数
- yum 安装php遇到php53-common conflicts with php-common
- jQuery Validation范例