javascript protype 属性

 

 

函数(functions)在javascript中本身就是对象,它有方法和属性。关于函数的属性,prototype是比较重要的一个。

Js代码 

function foo(a,b){  

  return a*b;  

}  

typeof foo.prototype;//object  

 

可以为prototype添加属性,

Js代码 

foo.prototype={}  

这个属性对foo函数没有任何影响,仅仅当foo作为构造函数的时候。prototype才会有意义.

 

给prototype添加属性和方法

 

前几节学过的用构造函数创建对象,主要的思路还是用new操作符访问this。这个this包含了构造函数返回的对象。我们可以往this里添加属性和方法也就是,也就是给这个对象添加了属性和方法。让我们看看下列的代码

Js代码 

function Gadget(name,color){  

    this.name=name;  

    this.color=color;  

    this.whatAreYou=function(){  

        return 'I am a '+this.color+' '+this.name;  

    }  

}  

 添加属性和方法到prototype中,是另一种给对象添加功能的方法。让我们添加下price和rating和getInfo().

Js代码 

Gedget.prototype.price = 100;  

Gedget.prototype.rating= 3;  

Gedget.prototype.getInfo=function(){  

     return 'Rating: '+this.rating+',price: '+this.price;  

}  

 如果你感觉这么写很麻烦我们也可以用到以前创建对象所用到的方法

Js代码 

Gadget.prototype = {  

  price: 100,  

  rating: 3,  

  getInfo: function() {  

    return 'Rating: ' + this.rating + ', price: ' + this.price;  

  }  

};  

 这两种方法都是一样的。

 

调用Prototype的属性和方法

 

所有的属性和方法都可以添加到prototype中,对于对象是直接可以访问的。如果创建了一个对象,就可以访问所有的属性和方法了。

Js代码 

var newtoy = new Gadget('webcam','black');  

newtoy.name;//webcam  

newtoy.color;//black  

newtoy.whatAreYou();//I am black webcam  

newtoy.price;//100  

newtoy.rating;//3  

newtoy.getInfo();//Rating:3,price:100  

对象的传递,实质上传递的是个引用,也就意味这每次创建个对象,prototype属性并不是复制而成,这样就可以动态的修改prototype的属性,所有创造的对象的属性也就会随着prototype的更改而更改。代码如下

Js代码 

Gadget.prototype.get=function(what){  

   return this[what];  

}  

 

newtoy.get('price');//100  

newtoy.get('color');//'black'  

 newtoy对象是在get方法建立之前而生成的,但是newtoy还是可以访问get方法的。这就是prototype的妙处。

 

自身属性和prototype属性的对比

 

在上个例子中getInfo这个方法,用的是this来调用rating和price的。当然也可以用Gedget.prototype来重写这个方法

Js代码 

Gadget.prototype.getInfo = function() {  

return 'Rating: ' + Gadget.prototype.rating + ', price: ' + Gadget.prototype.price;  

};  

这个上面的方法有什么不同?首先要了解prototype更多的细节问题.

Js代码 

var newtoy = new Gadget('webcam','black');  

 当访问newtoy.name的时候,Javascript引擎会检索这个对象的所有属性直到找到name的属性,并返回它的值。

 

Js代码 

newtoy.name;//webcam  

如果访问rating会怎么样呢?Javascript引擎首先会检索这个对象的所有属性,发现并没有叫rating这个属性。然后再去找创造这个对象的构造函数的prototype(也就是newtoy.constructor.prototype).如果这个属性找到就返回。

Js代码 

newtoy.rating;//3  

当然这么访问和如下代码是一样的

Js代码 

newtoy.constructor.prototype.rating;//3  

对prototype的属性进行重写

 

前几个例子说明了如果没有自身的属性,就会找prototype的属性。下面引出了这样一个问题,如果自身的属性和prototype的属性都一样的话,会怎么样呢。看如下代码

Js代码 

function Gadget(name) {  

  this.name = name;  

}  

Gadget.prototype.name = 'foo';//foo  

 在创建一个新的对象

Js代码 

var toy = new Gadget('camera');  

toy.name;//camera  

 发现了toy.name的值是camera.这就相对于prototype的name属性进行重写。

Js代码 

delete toy.name;//true  

toy.name;//foo  

 如果删除自身属性name,prototype的属性name就生效了

 当然你可以重新创建toy的属性

Js代码 

toy.name='camera';  

toy.name;//camera  

穷举属性(Enumerating Properties)

 

要列出对象所有的属性可以用for.in循环来做

Js代码 

var o = {p1: 1, p2: 2};  

for (var i in o) {  

  console.log(i + '=' + o[i]);  

}  

 结果为:p1=1,p2=2

 

但是有以下几点需要注意

并不能把对象的所有属性列出来。像constructor属性就没有。可以列出的属性我们叫它可以枚举的(enumerable),可以用propertyIsEnumerable()方法来判断属性是否可以列出来。

可以把prototype的属性列出来,如果要判断对象的自身属性可以用hasOwnProperty() 方法

虽然可以列出所有prototype的属性,但是如果使用propertyIsEnumerable()方法来校验prototype的属性,它的返回结果都是false.

让我们看个综合例子就明白了

Js代码 

function Gadget(name, color) {  

  this.name = name;  

  this.color = color;  

  this.someMethod = function(){return 1;}  

}  

Gadget.prototype.price = 100;  

Gadget.prototype.rating = 3;  

 创建一个新的对象

Js代码 

var newtoy = new Gadget('webcam','black');  

Js代码 

for (var prop in newtoy) {   

  console.log(prop + ' = ' + newtoy[prop]);   

}  

 结果为

   name = webcam

   color = black

   someMethod = function () { return 1; }

   price = 100

   rating = 3

 如果要区分自身属性和prototype属性,那就用hasOwnProperty()方法

 

Js代码 

for (var prop in newtoy) {   

  if (newtoy.hasOwnProperty(prop)) {  

    console.log(prop + '=' + newtoy[prop]);   

  }  

}  

 结果为

  name=webcam

  color=black

  someMethod=function () { return 1; }

 再来看一下propertyIsEnumerable的方法

Js代码 

newtoy.propertyIsEnumerable('name');//true  

 大部分内置的属性和方法都是不可以列举的

Js代码 

newtoy.propertyIsEnumerable('constructor');//false  

 任何的属性来自prototype的都不能被列举

Js代码 

newtoy.propertyIsEnumerable('price');//false  

 如果进入prototype内部去调用属性就可以被列举了

Js代码 

newtoy.constructor.prototype.propertyIsEnumerable('price');//true  

 

扩展内置对象

 

内置对象就是由构造函数Array,String,Object。函数可以扩展它们的prototype,也就意味着你可以通过prototype添加Array的功能。

Js代码 

Array.prototype.inArray = function(needle) {  

  for (var i = 0, len = this.length; i < len; i++) {  

    if (this[i] === needle) {  

      return true;  

    }  

  }  

  return false;  

}  

 现在所有的Array都有了新的方法。

Js代码 

var a = ['red', 'green', 'blue'];  

a.inArray('red');//true  

a.inArray('yellow');//false  

 通过prototype扩展Array的功能真是很简单的事情。

 

关于扩展内置对象的讨论

Prototype库是个比较有名的javascript库,它通过这种方法,把javascript变成了类似ruby的语言。但是YUI却反对这种做法。如果你会使用Javascript,一般希望用javascript正常的写法,改变了核心方法,会对开发人员造成许多困惑。

现在的javascript和浏览器功能都逐渐的增多,本身开发人员对Javascript核心的扩展,很可能明天就会没什么用处了。最佳实践是先判断核心的功能是否存在,然后再去扩展。如:

Js代码 

if (!String.prototype.reverse) {  

  String.prototype.reverse = function() {     

    return Array.prototype.reverse.apply(this.split('')).join('');   

  }   

}  

 关于prototype令人迷惑的地方

 

Js代码 

function Dog(){  

    this.tail=true;  

}  

var benji = new Dog();  

var rusty = new Dog();  

Dog.prototype.say = function(){  

    return 'Woof';  

}  

benji.say();//Woof   

rusty.say();//Woof  

benji.constructor;//Dog()  

rusty.constructor;//Dog()  

benji.constructor.prototype.constructor;//Dog()  

typeof benji.constructor.prototype.tail;//undefined  

 

Dog.prototype={paws:4,hair:true};  

//Dog.prototype.constructor = Dog;  

typeof benji.paws;//undefined  

alert(benji.say());//Woof  

 

var lucy = new Dog();//new object  

alert(lucy.paws);  

alert(lucy.tail)  

 

lucy.constructor;//Object();  

benji.constructor;//Dog():  

 

typeof lucy.constructor.prototype.paws;//undefined  

typeof benji.constructor.prototype.paws;//number  

新建一个构造函数并创建两个对象

Js代码 

function Dog(){  

    this.tail=true;  

}  

var benji = new Dog();  

var rusty = new Dog();  

建完对象之后,我们仍然可以添加属性到prototype中,对象可以访问这个新添加的属性

Js代码 

Dog.prototype.say = function(){  

    return 'Woof';  

}  

benji.say();//Woof   

rusty.say();//Woof  

 让我们来看看创建对象的构造函数,一起看来很正常

Js代码 

benji.constructor;//Dog()  

rusty.constructor;//Dog()  

 看如下代码很有意思的事情发生了。。。。。

Js代码 

benji.constructor.prototype.constructor;//Dog()  

当我们想知道prototype的构造函数是啥的时候,问题出现了。。。结果是Dog()。但是这不完全正确。prototype对象仅仅是个Object对象,他并没有任何关于Dog的属性。。。测试看看

Js代码 

typeof benji.constructor.prototype.tail;//undefined  

让我们继续深入下去。当完全重写prototype对象时看看会怎么样。

Js代码 

Dog.prototype={paws:4,hair:true};  

发现了以前创造的对象竟然访问不了新的prototype的属性。。。

Js代码 

typeof benji.paws;//undefined  

benji.say();//Woof  

说明了旧的对象还是指向以前的Prototype了。

让我们新建一个对象看看会怎样

Js代码 

var lucy = new Dog();//new object  

lucy.say();//TypeError:lucy.say is not a function  

lucy.paws;//4  

说明新建的对象已经指向新的prototype了。

但是lucy这个对象的构造函数变成了object

Js代码 

lucy.constructor;//Object();  

benji.constructor;//Dog():  

最令人感到困扰的是prototype的属性

Js代码 

typeof lucy.constructor.prototype.paws;//undefined  

typeof benji.constructor.prototype.paws;//number  

所以如果想完全重写prototype属性,建议用以下的方式。

Js代码 

Dog.prototype={paws:4,hair:true};  

Dog.prototype.constructor=Dog;  

 这样就不会造成以上的困扰了。。。。

来之:javaeye 的http://xiayuanfeng.javaeye.com/blog/

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值