《悟透javascript》学习笔记:十、原型扩展

引言

 

想必君的悟性极高,可能你会这样想:如果在JavaScript 内置的那些如Object Function等函数的prototype上添加些新的方法和属性,是不是就能扩展JavaScript的功能呢?

    那么,恭喜你,你得到了!

 

闭包模型

 

<script language="javascript">

function person(){   

   this.age = 52;        //使用this声明的属性是公有属性

   var name = "bill";         //使用var声明的属性是私有属性

   this.show = function(){alert("hello, i'm " + name);}           //公有方法

   var say = function(){alert(name + " are " + this.age + " years old");}   //私有方法

}

 

var p = new person();

p.show();      //可以访问

alert(p.age);  //可以访问

p.say();   //错误

alert(p.name);     //错误

</script>

 

微软在设计 AJAX 类库的初期,用了一种被称为“闭包”(closure)的技术来模拟“类”。其大致模型如上。这是对类的一个很形象的模拟。但是前面我们说过,给每一个对象设置一份方法是一种很大的浪费。还有,“闭包”这种间接保持变量值的机制,往往会给JavaSript的垃圾回收器制造难题。特别是遇到对象间复杂的循环引用时,垃圾回收的判断逻辑非常复杂。无独有偶,IE浏览器早期版本确实存在JavaSript垃圾回收方面的内存泄漏问题。再加上“闭包”模型在性能测试方面的表现不佳,微软最终放弃了“闭包”模型,而改用“原型”模型。

 

所谓的“闭包”,就是在构造函数体内定义另外的函数作为目标对象的方法函数,而这个对象的方法函数反过来引用外层外层函数体中的临时变量。这使得只要目标对象在生存期内始终能保持其方法,就能间接保持原构造函数体当时用到的临时变量值。尽管最开始的构造函数调用已经结束,临时变量的名称也都消失了,但在目标对象的方法内却始终能引用到该变量的值,而且该值只能通这种方法来访问。即使再次调用相同的构造函数,但只会生成新对象和方法,新的临时变量只是对应新的值,和上次那次调用的是各自独立的。的确很巧妙!

 

原型模型

 

<script language="javascript">

function person(name){

   this.name = name;

}

person.prototype.say = function(){alert("hello, i'm " + this.name);}

 

function employee(name, salary){

   //调用person作为employee的构造函数——重点

   person.call(this, name);      //目的是继承person的属性

   this.salary = salary;

}

//子类构造函数首先需要用上层构造函数来建立 prototype对象,实现继承的概念——重点

employee.prototype = new person(); //目的是继承person的方法,只需要其 prototype 的方法,此对象的成员没有任何意义!

employee.prototype.showMoney = function(){alert(this.name + "'s salary is " + this.salary);}

 

var bill = new person("BillGates");

bill.say();

 

var jeck = new employee("jeck baoer", 5000);

jeck.showMoney();

jeck.say();

</script>

 

原型类模型虽然不能模拟真正的私有变量,而且也要分两部分来定义类,显得不怎么“优雅”。不过,对象间的方法是共享的,不会遇到垃圾回收问题,而且性能优于“闭包”模型。正所谓“有失必有得”嘛。

 

      上面的模型有两个重点:

1.       person.call(this, name); 这句的目的是调用person作为employee的构造函数,从而使employee继承到person的属性,如果你注释掉该句,将会发现无法访问到person里的name属性(其实就是为了继承父类的this

2.       employee.prototype = new person(); 目的是为了继承person的方法,如果你注释掉这句将发现无法调用person上的方法。而这句话的背后是为了将employeeprototype设置为new personprototype,这样就可以通过“原型链”的方式使用person的方法了,所以也可以这样写employee.prototype = person.prototype;效果是一样的。(其实就是为了继承父类的prototype

 

在原型模型中,为了实现类继承,必须首先将子类构造函数的prototype设置为一个父类的对象实例。创建这个父类对象实例的目的就是为了构成原型链,以起到共享上层原型方法作用。但创建这个实例对象时,上层构造函数也会给它设置对象成员,这些对象成员对于继承来说是没有意义的。虽然,我们也没有给构造函数传递参数,但确实创建了若干没有用的成员,尽管其值是undefined,这也是一种浪费啊。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值