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

但是,这个并不能体现OOP思想,看了原型与原型链之后觉得OOP一目了然:

  1. 1 var Calculator = function (decimalDigits, tax) {
  2. 2 this.decimalDigits = decimalDigits;
  3. 3 this.tax = tax;
  4. 4 };

然后给Calculator的prototype属性赋值对象字面量来设定Calculator对象的原型。(个人觉得这里的原型就如同C#中类的概念,prototype则是用来给类添加属性,方法的)

  1. Calculator.prototype = {
  2. add: function (x, y) {
  3. return x + y;
  4. },
  5.  
  6. subtract: function (x, y) {
  7. return x - y;
  8. }
  9. };
  10. //alert((new Calculator()).add(1, 3));

这样,通过new 一个对象就可以调用里面的公开的方法,属性。

原型使用方式2

  1. 当我们把一堆方法写到Calculator中,但是有些方法我们不想对外公开,即实现public/private,那么我们只能返回公开的方法:
  1. 1 var Calculaotr = function(x, y) {
  2. 2 this.x = x;
  3. 3 this.y = y;
  4. 4 };
  5. 5 Calculaotr.prototype = function() {
  6. 6 add= function (x,y) {
  7. 7 return x + y;
  8. 8 },
  9. 9 subtract=function (x,y) {
  10. 10 return x - y;
  11. 11 }
  12. 12 return {
  13. 13 A:add,
  14. 14 S:subtract
  15. 15 }
  16. 16 }();

这里用利用函数自执行在加载文件同时,执行上面的JS代码,那么我们就可以访问对外公开的方法和属性,如果不通过自执行,则会报异常:

在C#中,我们可能会遇到这样的情况,类A的一个属性是类B型,在JS中,可以通过以下方式实现:

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

这里我们可以看到Calculator的原型是指向到BaseCalculator的一个实例上,目的是让Calculator集成它的add(x,y)和subtract(x,y)这2个function,

还有一点要说的是,由于它的原型是BaseCalculator的一个实例,所以不管你创建多少个Calculator对象实例,他们的原型指向的都是同一个实例。

如果我们不想让Calculator对象访问BaseCalculator的decimalDigits属性,可以这样:

  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. };
  15. Calculator.prototype =new prototype;

通过以上两种原型使用方式,结合C#中的继承,不难想到JS中如何重写原型。

重写原型:

在项目中,引入外部JS库,但是有些方法并不是我们想要的,此时我们通过重写原型,就可以达到我们想要的结果:

  1. //重写原型
  2. Calculaotor.prototype.add = function(x, y) {
  3. return x + y + this.tax;
  4. }

原型链

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

上面的例子中,test 对象从 Bar.prototype 和 Foo.prototype 继承下来;因此,它能访问 Foo 的原型方法 method。同时,它也能够访问那个定义在原型上的 Foo 实例属性 value。需要注意的是 new Bar() 不会创造出一个新的 Foo 实例,而是重复使用它原型上的那个实例;因此,所有的 Bar 实例都会共享相同的 value 属性。

属性查找

当查找一个对象的属性时,会遍历原型链,一直往顶层Object找,如果没有找到,则返回undefined.

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

以上add函数返回的是3,而不是13则说明,属性查找时,优先查找自己的属性。然后在往上一级找,最后找Object,这样看来,在遍历时用for in效率就是个问题。

还有一点,我们可以赋值任何类型的对象到原型上,但是不能赋值原子类型的值,比如如下代码是无效的:

  1. function Foo() {}
  2. Foo.prototype = 1; // 无效

hasOwnProperty函数

hasOwnProperty是判断一个对象是否包含自定义属性而不是原型链上的属性,是JS中唯一一个查找属性,但不查找原型链的函数。

但是JS不会保护hasOwnProperty函数,如果刚好某个对象中也有hasOwnProperty函数,则我们可以通过以下方式正确获得想要的结果:

  1. alert({}.hasOwnProperty.call(c, 'tax'));//返回true

这里的c是Calculator的一个对象,tax是我们要找的属性。

当我面在for in loop 语句中查找属性时,用hasOwnProperty函数,提高效率:

  1. 1 Object.prototype.bar = 1;
  2. 2 var foo={moo : 1}
  3. 3 for (var i in foo) {
  4. 4 if(foo.hasOwnProperty(i)) {
  5. 5 alert(console.log(i));
  6. 6 }
  7. 7 }//此时只会输出moo属性

JS原型和原型链的更多相关文章

  1. Js 原型和原型链

    Js中通过原型和原型链实现了继承 Js对象属性的访问,首先会查找自身是否拥有这个属性 如果查到,则返回属性值,如果找不到,就会遍历原型链,一层一层的查找,如果找到就会返回属性值 直到遍历完Object ...

  2. 【repost】JS原型与原型链终极详解

    一. 普通对象与函数对象  JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象.下面举例说明 function f ...

  3. JS原型与原型链终极详解

    一. 普通对象与函数对象  JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object ,Function 是JS自带的函数对象.下面举例说明 function f ...

  4. JS原型与原型链终极详解(转)

    JavaScript原型及原型链详解 一. 普通对象与函数对象 JavaScript 中,万物皆对象!但对象也是有区别的.分为普通对象和函数对象,Object,Function 是JS自带的函数对象. ...

  5. 总结一下js的原型和原型链

    最近学习了js的面向对象编程,原型和原型链这块是个难点,理解的不是很透彻,这里搜集了一些这方面的资料,以备复习所用 一. 原型与构造函数 Js所有的函数都有一个prototype属性,这个属性引用了一 ...

  6. 深入JS原型与原型链

    要了解原型和原型链,首先要理解普通对象和函数对象. 一.普通对象和函数对象的区别 在Javascript的世界里,全都是对象,而对象之间也是存在区别,我们首先区分一下普通对象和函数对象,如下代码: f ...

  7. JS对象、原型链

    忘记在哪里看到过,有人说鉴别一个人是否 js 入门的标准就是看他有没有理解 js 原型,所以第一篇总结就从这里出发. 对象 JavaScript 是一种基于对象的编程语言,但它与一般面向对象的编程语言 ...

  8. JS面向对象之原型链

      对象的原型链 只要是对象就有原型 原型也是对象 只要是对象就有原型, 并且原型也是对象, 因此只要定义了一个对象, 那么就可以找到他的原型, 如此反复, 就可以构成一个对象的序列, 这个结构就被成 ...

  9. JS 原型与原型链

    图解: 一.普通对象 跟 函数对象 JavaScript 中,一切皆对象.但对象也有区别,分为 普通对象 跟 函数对象,Object 和 Function 是 JavaScript 自带的函数对象. ...

随机推荐

  1. 二十五、oracle pl/sql进阶--控制结构(分支,循环,控制)

    一.pl/sql的进阶--控制结构在任何计算机语言(c,java,pascal)都有各种控制语句(条件语句,循环结构,顺序控制结构...),在pl/sql中也存在这样的控制结构.在本部分学习完成后,希 ...

  2. php 常用的调试方法

    file_put_contents("c:\1.log","输出字符串",FILE_APPEND);第三个参数是防止前面的内容被覆盖 error_log(pri ...

  3. jquery里面的attr和css来设置轮播图竟然效果不一致

    /*封装$*/ // window.$=HTMLElement.prototype.$=function(selector){ // var elems=(this==window?document: ...

  4. js数组对象方法

  5. seajs简记

    参考seajs快速入门 一.前端模块化的价值 解决命名冲突 摆脱文件依赖 性能优化 提高可维护性 seajs.use方法调用通过exports暴露接口通过require引入依赖 二.Sea.js 的常 ...

  6. Flask-Request对象属性

    Request属性 元属性 method host path environ headers data body中的内容 最安全 解析后 remote_addr args form values  a ...

  7. kettle连接Hive中数据导入导出(6)

    1.hive往外写数据 http://wiki.pentaho.com/display/BAD/Extracting+Data+from+Hive+to+Load+an+RDBMS 连接hive

  8. [转]5个JavaScript面试题

    问题1:闭包 考虑下面的代码: 1 2 3 4 5 6 var nodes = document.getElementsByTagName('button'); for (var i = 0; i & ...

  9. linux双线ip设置(不需额外增加路由表)

    linux 双线ip设置(不需额外增加路由表,只需修改下面就ok了)修改   vi /etc/iproute2/rt_tables              (增加电信和网通两个路由表) 增加252  ...

  10. mysql高级查询

    高级查询: 1.连接查询 select * from Info,Nation #得出的结果称为笛卡尔积select * from Info,Nation where Info.Nation = Nat ...