Javascript 之 Prototype

1. Prototype 属性

JavaScript 中的 function 本质就是一个 object 对象,它本身包含了一些方法(apply(),call())和一些属性(length, constructor),这其中还包含一个名为 prototype 的属性。 当你定义了一个 function 后,你就能访问到这个 prototype 属性,它的初始值是一个”空”的 object 对象:

{ … }typeof foo.prototype;// “object”

你可以随意设定这个对象,给它加上属性或者方法,但是这不会对这个 function 本身造成任何影响,除非你把它作为构造函数来使用。

使用 prototype 来添加方法和属性

当使用 new 来实例化一个对象时,在 function 内可以通过 this 关键字来对这个对象进行成员追加:

{ this.name = name; this.color = color; + this.color + ‘ ‘ + this.name; };}

另外我们也可以在 function 的 prototype 属性上进行相同的处理:

Gadget.prototype.price = 100;Gadget.prototype.rating = 3;Gadget.prototype.getInfo = + this.rating + ‘, price: ‘ + this.price;};

prototype 对象甚至可以被整个替换:

Gadget.prototype = { price: 100, rating: … /* 其他成员… */};2. 使用 prototype 的方法和属性

prototype 上添加的方法和属性都能够在实例化后的对象上调用:

var newtoy = new Gadget(‘webcam’, ‘black’);newtoy.name;// “webcam”newtoy.color;// “black”newtoy.whatAreYou();// “I am a black webcam”newtoy.price;// 100newtoy.rating;// 3newtoy.getInfo();// “Rating: 3, price: 100”

object 对象在 Javascript 中都是以引用方式传递的,所以 prototype 并非在每个实例对象中保存一份。当你改变 prototype 时,所有的实例对象都能立即“察觉”这些变动。假设我们再增加一个新的方法:

Gadget.prototype.get = [what];};

前文的 newtoy 虽然在此前已经被实例化,但他仍然能使用到这个新方法:

newtoy.get(‘price’);// 100newtoy.get(‘color’);// “black”自有属性 与 prototype 属性

先前我们定义过一个 getInfo() 方法,它修改为以下的方式后也能获得同样的输出结果:

Gadget.prototype.getInfo = + Gadget.prototype.rating + ‘, price: ‘ + Gadget.prototype.price;};

这个原由需要从头说起,先来看 newtoy 对象是怎样实例化的:

var newtoy = new Gadget(‘webcam’, ‘black’);

当你访问 newtoy 的某个属性的时候(这里假设是 newtoy.name),JavaScript 引擎会搜索它的所有名为 name 的属性,如果发现了就返回它的值:

newtoy.name;// “webcam”

当你访问 rating 属性时情况变了,JavaScript 引擎在 newtoy 上找不到名为 rating 的属性,然后他就会到 newtoy 的构造函数(Gadget) 的 prototype 属性上继续查找:

newtoy.rating;// 3

以下的代码验证了这一点:

newtoy.constructor === Gadget;// truenewtoy.constructor.prototype.rating;// 3

我们知道每个 object 对象都有一个构造函数,那么作为 object 对象的 prototype 也必然存在一个构造函数。这就形成了一个 prototype chain (prototype 链),这个链的最上层就是内置的 Object() 对象。 要验证这一点很容易,newtoy 没有 toString() 方法,它的 prototype 上也没有,但是你却能调用 newtoy.toString() ,,因为 object 对象有这个方法:

newtoy.toString();// “[object Object]”自有属性复写 prototype 属性

当自有属性与 prototype 属性重名时,自有属性优先:

{ this.name = name;}Gadget.prototype.name = ‘mirror’;var toy = new Gadget(‘camera’);toy.name;// “camera”

使用 hasOwnProperty() 可以知道某个属性知否是自有属性:

toy.hasOwnProperty(‘name’);// true

我们把自有属性 name 删了再瞧瞧什么情况:

delete toy.name;// truetoy.name;// “mirror”toy.hasOwnProperty(‘name’);// falseEnumerating properties

使用 for-in 语句能够遍历出一个对象的所有属性:

虽然 for-in 也适用于数组,但建议遍历数组时采用 for,遍历对象时采用 for-in。

var params = { productid: 666, section: ‘products’};var url = ‘http://example.org/page.php?’,i,query = [];for (i in params) { query.push(i + ‘=’ + params[i]);}url += query.join(‘&’);

以上代码输出: ?productid=666&section=products

以下几点需要注意:

通过实例来看一下:

{ this.name = name; this.color = color; .name; };}Gadget.prototype.price = 100;Gadget.prototype.rating = 3;var newtoy = new Gadget(‘webcam’, ‘black’);for (var prop in newtoy) { console.log(prop + ‘ = ‘ + newtoy[prop]);}// 输出name = webcamcolor = blackgetName = .name;}price = 100rating = 3

再试一下 propertyIsEnumerable() 方法:

// 自有属性newtoy.propertyIsEnumerable(‘name’);// true// 内置属性newtoy.propertyIsEnumerable(‘constructor’);// false// prototype 链上的属性newtoy.propertyIsEnumerable(‘price’);// false// 改变调用对象后newtoy.constructor.prototype.propertyIsEnumerable(‘price’);// trueisPrototypeOf()如果雨后还是雨,如果忧伤过后还是忧伤,

Javascript 之 Prototype

相关文章:

你感兴趣的文章:

标签云: