JS原型和原型链

- 1 var decimalDigits = 2,
- 2 tax = 5;
- 3
- 4 function add(x, y) {
- 5 return x + y;
- 6 }
- 7
- 8 function subtract(x, y) {
- 9 return x - y;
- 10 }
- 11
- 12 //alert(add(1, 3));

但是,这个并不能体现OOP思想,看了原型与原型链之后觉得OOP一目了然:
- 1 var Calculator = function (decimalDigits, tax) {
- 2 this.decimalDigits = decimalDigits;
- 3 this.tax = tax;
- 4 };
然后给Calculator的prototype属性赋值对象字面量来设定Calculator对象的原型。(个人觉得这里的原型就如同C#中类的概念,prototype则是用来给类添加属性,方法的)

- Calculator.prototype = {
- add: function (x, y) {
- return x + y;
- },
- subtract: function (x, y) {
- return x - y;
- }
- };
- //alert((new Calculator()).add(1, 3));

这样,通过new 一个对象就可以调用里面的公开的方法,属性。
原型使用方式2
- 当我们把一堆方法写到Calculator中,但是有些方法我们不想对外公开,即实现public/private,那么我们只能返回公开的方法:

- 1 var Calculaotr = function(x, y) {
- 2 this.x = x;
- 3 this.y = y;
- 4 };
- 5 Calculaotr.prototype = function() {
- 6 add= function (x,y) {
- 7 return x + y;
- 8 },
- 9 subtract=function (x,y) {
- 10 return x - y;
- 11 }
- 12 return {
- 13 A:add,
- 14 S:subtract
- 15 }
- 16 }();

这里用利用函数自执行在加载文件同时,执行上面的JS代码,那么我们就可以访问对外公开的方法和属性,如果不通过自执行,则会报异常:
在C#中,我们可能会遇到这样的情况,类A的一个属性是类B型,在JS中,可以通过以下方式实现:

- 1 var BaseCalculator = function() {
- 2 this.decimalDigits = 2;
- 3 };
- 4 BaseCalculator.prototype = {
- 5 A: function(x, y) {
- 6 return x + y;
- 7 },
- 8 S: function(x, y) {
- 9 return x - y;
- 10 }
- 11 };
- 12 var Calculator = function() {
- 13 this.tax = 3;
- 14 };
- 15Calculator.prototype = new BaseCalculator();

这里我们可以看到Calculator的原型是指向到BaseCalculator的一个实例上,目的是让Calculator集成它的add(x,y)和subtract(x,y)这2个function,
还有一点要说的是,由于它的原型是BaseCalculator的一个实例,所以不管你创建多少个Calculator对象实例,他们的原型指向的都是同一个实例。
如果我们不想让Calculator对象访问BaseCalculator的decimalDigits属性,可以这样:

- var BaseCalculator = function() {
- this.decimalDigits = 2;
- };
- BaseCalculator.prototype = {
- A: function(x, y) {
- return x + y;
- },
- S: function(x, y) {
- return x - y;
- }
- };
- var Calculator = function() {
- this.tax = 3;
- };
- Calculator.prototype =new prototype;

通过以上两种原型使用方式,结合C#中的继承,不难想到JS中如何重写原型。
重写原型:
在项目中,引入外部JS库,但是有些方法并不是我们想要的,此时我们通过重写原型,就可以达到我们想要的结果:
- //重写原型
- Calculaotor.prototype.add = function(x, y) {
- return x + y + this.tax;
- }
原型链

- 1 function Foo() {
- 2 this.value = 42;
- 3 }
- 4 Foo.prototype = {
- 5 method: function() {}
- 6 };
- 7
- 8 function Bar() {}
- 9
- 10 // 设置Bar的prototype属性为Foo的实例对象
- 11 Bar.prototype = new Foo();
- 12 Bar.prototype.foo = 'Hello World';
- 13
- 14 // 修正Bar.prototype.constructor为Bar本身
- 15 Bar.prototype.constructor = Bar;
- 16
- 17 var test = new Bar() // 创建Bar的一个新实例
- 18
- 19 // 原型链
- 20 test [Bar的实例]
- 21 Bar.prototype [Foo的实例]
- 22 { foo: 'Hello World' }
- 23 Foo.prototype
- 24 {method: ...};
- 25 Object.prototype
- 26 {toString: ... /* etc. */};

上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是重复使用它原型上的那个实例;因此,所有的 Bar 实例都会共享相同的 value 属性。
属性查找
当查找一个对象的属性时,会遍历原型链,一直往顶层Object找,如果没有找到,则返回undefined.

- 1 function foo() {
- 2 this.add = function (x, y) {
- 3 return x + y;
- 4 }
- 5 }
- 6
- 7 foo.prototype.add = function (x, y) {
- 8 return x + y + 10;
- 9 }
- 10
- 11 Object.prototype.subtract = function (x, y) {
- 12 return x - y;
- 13 }
- 14
- 15 var f = new foo();
- 16 alert(f.add(1, 2)); //结果是3,而不是13
- 17 alert(f.subtract(1, 2)); //结果是-1

以上add函数返回的是3,而不是13则说明,属性查找时,优先查找自己的属性。然后在往上一级找,最后找Object,这样看来,在遍历时用for in效率就是个问题。
还有一点,我们可以赋值任何类型的对象到原型上,但是不能赋值原子类型的值,比如如下代码是无效的:
- function Foo() {}
- Foo.prototype = 1; // 无效
hasOwnProperty函数
hasOwnProperty是判断一个对象是否包含自定义属性而不是原型链上的属性,是JS中唯一一个查找属性,但不查找原型链的函数。
但是JS不会保护hasOwnProperty函数,如果刚好某个对象中也有hasOwnProperty函数,则我们可以通过以下方式正确获得想要的结果:
- alert({}.hasOwnProperty.call(c, 'tax'));//返回true
这里的c是Calculator的一个对象,tax是我们要找的属性。
当我面在for in loop 语句中查找属性时,用hasOwnProperty函数,提高效率:

- 1 Object.prototype.bar = 1;
- 2 var foo={moo : 1}
- 3 for (var i in foo) {
- 4 if(foo.hasOwnProperty(i)) {
- 5 alert(console.log(i));
- 6 }
- 7 }//此时只会输出moo属性
JS原型和原型链的更多相关文章
- Js 原型和原型链
Js中通过原型和原型链实现了继承 Js对象属性的访问,首先会查找自身是否拥有这个属性 如果查到,则返回属性值,如果找不到,就会遍历原型链,一层一层的查找,如果找到就会返回属性值 直到遍历完Object ...
- 【repost】JS原型与原型链终极详解
一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象.下面举例说明 function f ...
- JS原型与原型链终极详解
一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象.下面举例说明 function f ...
- JS原型与原型链终极详解(转)
JavaScript原型及原型链详解 一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object,Function 是JS自带的函数对象. ...
- 总结一下js的原型和原型链
最近学习了js的面向对象编程,原型和原型链这块是个难点,理解的不是很透彻,这里搜集了一些这方面的资料,以备复习所用 一. 原型与构造函数 Js所有的函数都有一个prototype属性,这个属性引用了一 ...
- 深入JS原型与原型链
要了解原型和原型链,首先要理解普通对象和函数对象. 一.普通对象和函数对象的区别 在Javascript的世界里,全都是对象,而对象之间也是存在区别,我们首先区分一下普通对象和函数对象,如下代码: f ...
- JS对象、原型链
忘记在哪里看到过,有人说鉴别一个人是否 js 入门的标准就是看他有没有理解 js 原型,所以第一篇总结就从这里出发. 对象 JavaScript 是一种基于对象的编程语言,但它与一般面向对象的编程语言 ...
- JS面向对象之原型链
对象的原型链 只要是对象就有原型 原型也是对象 只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成 ...
- JS 原型与原型链
图解: 一.普通对象 跟 函数对象 JavaScript 中,一切皆对象.但对象也有区别,分为 普通对象 跟 函数对象,Object 和 Function 是 JavaScript 自带的函数对象. ...
随机推荐
- 二十五、oracle pl/sql进阶--控制结构(分支,循环,控制)
一.pl/sql的进阶--控制结构在任何计算机语言(c,java,pascal)都有各种控制语句(条件语句,循环结构,顺序控制结构...),在pl/sql中也存在这样的控制结构.在本部分学习完成后,希 ...
- php 常用的调试方法
file_put_contents("c:\1.log","输出字符串",FILE_APPEND);第三个参数是防止前面的内容被覆盖 error_log(pri ...
- jquery里面的attr和css来设置轮播图竟然效果不一致
/*封装$*/ // window.$=HTMLElement.prototype.$=function(selector){ // var elems=(this==window?document: ...
- js数组对象方法
- seajs简记
参考seajs快速入门 一.前端模块化的价值 解决命名冲突 摆脱文件依赖 性能优化 提高可维护性 seajs.use方法调用通过exports暴露接口通过require引入依赖 二.Sea.js 的常 ...
- Flask-Request对象属性
Request属性 元属性 method host path environ headers data body中的内容 最安全 解析后 remote_addr args form values a ...
- kettle连接Hive中数据导入导出(6)
1.hive往外写数据 http://wiki.pentaho.com/display/BAD/Extracting+Data+from+Hive+to+Load+an+RDBMS 连接hive
- [转]5个JavaScript面试题
问题1:闭包 考虑下面的代码: 1 2 3 4 5 6 var nodes = document.getElementsByTagName('button'); for (var i = 0; i & ...
- linux双线ip设置(不需额外增加路由表)
linux 双线ip设置(不需额外增加路由表,只需修改下面就ok了)修改 vi /etc/iproute2/rt_tables (增加电信和网通两个路由表) 增加252 ...
- mysql高级查询
高级查询: 1.连接查询 select * from Info,Nation #得出的结果称为笛卡尔积select * from Info,Nation where Info.Nation = Nat ...