初涉JavaScript模式 (6) : 原型模式 【二】
原型与in操作符
有两种方式使用in操作符:单独使用和在for-in循环中使用。
在单独使用时,in操作符会遍历实例公开(可枚举)的属性,如果找到该指定属性则返回true,无论该指定属性是存在与实例中还是原型中。直接上代码:
```javascript
function Animal(){ }
Animal.prototype.name = "animal"
var tom = new Animal();
tom.age = 22;
console.log("name" in tom); //true
console.log("age" in tom); //true
```
以上代码虽然能够确定实例是否能够访问指定属性,但是我们不能确定指定属性到底是存在于实例上海市原型上,同时使用hasOwnPrototype()和in就可以确定指定属性到底是在实例上海市原型中。上代码:
```javascript
function Animal(){ }
Animal.prototype.name = "animal"
var tom = new Animal();
tom.age = 22;
function hasPrototypeProperty(object,name){
return !object.hasOwnProperty(name) && (name in object);
}
console.log(hasPrototypeProperty(tom,"name")); //true
console.log(hasPrototypeProperty(tom,"age")); //false
```
hasPrototypeProperty()方法只有当该属性只存在于原型上时才会返回true。
在使用for-in循环时,返回的是所有对象能够访问的,可枚举的属性。既包括实例本身的属性也包括实例原型上的属性。要取得对象上所有可枚举的实例属性,可以使用ECMAScript5的Object.keys()方法。这个方法接受一个对象作为参数,返回一个包含所有可枚举属性的字符串数组。上代码:
```javascript
function Animal(){
}
Animal.prototype.name = "animal"
Animal.prototype.canEat = true;
Animal.prototype.canRun = true;
var WangCai = new Animal();
console.log(Object.keys(WangCai)); // []
console.log(Object.keys(Animal.prototype)); //["name", "canEat", "canRun"]
```
如果你想得到所有的实例属性,无论它是否可枚举,可以使用Object.getOwnPropertyNames() 方法,代码如下:
```javascript
function Animal(){
}
Animal.prototype.name = "animal"
Animal.prototype.canEat = true;
Animal.prototype.canRun = true;
var WangCai = new Animal();
console.log(Object.keys(WangCai)); // []
console.log(Object.getOwnPropertyNames(Animal.prototype)); //["constructor", "name", "canEat", "canRun"]
```
Object.keys()和Object.getOwnPropertyNames() 方法都可以用来取代for-in循环,但是注意只有IE9+,FF 4+,Safari 5+,Opera 12+ ,Chrome支持。
更简单的原型语法
在前面的例子中,每给原型添加一个属性或方法都要敲一遍Animal.prototype,对于有代码洁癖的我,那是最受不了的,更好的做法是用一个对象字面量来重写prototype,代码如下:
```javascript
function Animal(name){
this.name = name;
}
Animal.prototype = {
canEat : true,
canRun : true,
say : function(){
console.log("oh ~~~~我的名字叫"+this.name);
}
};
var tom = new Animal("tom");
tom.say(); //oh ~~~~我的名字叫tom
console.dir(Animal.prototype.constructor); //function Object() { [native code] }
```
在上面的代码中,我们把Animal.prototype设置为一个以字面量形式创建的新对象。结果相同,但是我们发现constructor已经不再指向Animal了,而是指向Object的构造函数,上一篇中提到,每创建一个新函数,就会同时创建他的prototype对象,这个对象也会获得constructor属性。而我们在这里重写了prototype对象,因此constructor属性也就变成了新对象的constructor属性(指向Object的构造函数),不再指向Animal,这个时候constructor也就无法确定对象的类型了。(注意constructor就不再是存在于prototype上了)
我们也可以手动指定constructor,代码如下:
```javascript
function Animal(name){
this.name = name;
}
Animal.prototype = {
constructor: Animal,
canEat : true,
canRun : true,
say : function(){
console.log("oh ~~~~我的名字叫"+this.name);
}
};
```
以上代码,我们设置了一个constructor,从而确保了通过该属性能够访问到适当的值,但是这种方式重设constructor属性会导致它的[[enumerable]] 特性被设置为true。默认情况下,原生的constructor属性是不可枚举的。在支持ECMAScript 5的浏览器上你可以用 Object.defineProperty()。示例代码如下:
```javascript
function Animal(name){
this.name = name;
}
Animal.prototype = {
constructor: Animal,
canEat : true,
canRun : true,
say : function(){
console.log("oh ~~~~我的名字叫"+this.name);
}
};
//重新设置构造函数
Object.defineProperty(Animal.prototype,"constructor",{
enumerable : false,
value : Animal
});
```
原型的动态性
前面几篇包括上面的重写prototype都涉及到了原型的动态性,所以我在这里总结一下。原型是伴随着一个新函数的创建而创建的,原型本身和一个新的Object实例并无区别,只是他多了一个constructor属性,这个constructor属性是指向那个新函数的。注意,原型是伴随着函数(那个新函数)存在的,和具体的实例并无直接联系,故每一个由这个新函数(构造函数)创建的新实例都共享原型的属性和方法(公开的),这也就是原型继承的基本。原型模式和构造函数的每个方法都是一个新的Function实例有着本质的区别,每个新的实例并无具体的方法实现(原型上定义的方法),只是通过原型链接口来访问原型上的具体实现。但是值得注意的是,通过构造函数创建的新实例指向的原型都是当初创建时构造函数所指的那个原型,就算我们在实例化以后改变该构造函数的原型(如重新声明原型为{}),该实例的原型依然是当初那个原型。而上面我们就是以字面量的方式重写了该原型,所以也就切断了已有实例和现在原型的关系。
原生对象的原型
原型模式的重要性不仅体现在创建自定义类型方面,就连所有原生的引用类型,都是采用这种模式创建的。所有的原生引用类型(Object,Array,String...)都在其构造函数的原型上定义了方法。
通过原生对象的原型,不仅可以取得所有默认方法的引用,而且也可以定义新的方法,甚至可以重写默认方法(不推荐,如果出现冲突,将很难处理)。
原型对象的问题
原型模式也不是没有缺点,原型模式的最大缺点就是每个实例对原型的修改都会影响到所有继承自该原型的实例(通过该原型伴随的函数创建的实例)。可是实例一般都要有属于自己的全部属性,而这个问题也是有解决方式的(下一篇 呵呵)
后记
如果在文中发现错误,请指正。推荐一个JS学习群(群里都是大神) 239147101
初涉JavaScript模式 (6) : 原型模式 【二】的更多相关文章
- 初涉JavaScript模式 (7) : 原型模式 【三】
组合使用构造函数模式和原型模式 上篇,我们提到了原型模式的缺点,就是每个实例不能拥有自己的属性,因为纯原型模式所有的属性都是公开给每个实例的,故我们可以组合使用构造函数模式和原型模式.构造函数用来定义 ...
- 初涉JavaScript模式 (5) : 原型模式 【一】
什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...
- 理解javascript中的原型模式
一.为什么要用原型模式. 早期采用工厂模式或构造函数模式的缺点: 1.工厂模式:函数creatPerson根据接受的参数来构建一个包含所有必要信息的person对象,这个函数可以被无数次的调用,工厂 ...
- 浅谈JavaScript中的原型模式
在JavaScript中创建对象由很多种方式,如工厂模式.构造函数模式.原型模式等: <pre name="code" class="html">/ ...
- javascript 面向对象编程(工厂模式、构造函数模式、原型模式)
javascript 面向对象编程(工厂模式.构造函数模式.原型模式) CreateTime--2018年3月29日17:09:38 Author:Marydon 一.工厂模式 /** * 工厂模 ...
- JavaScript之面向对象学习六原型模式创建对象的问题,组合使用构造函数模式和原型模式创建对象
一.仔细分析前面的原型模式创建对象的方法,发现原型模式创建对象,也存在一些问题,如下: 1.它省略了为构造函数传递初始化参数这个环节,结果所有实例在默认的情况下都将取得相同的属性值,这还不是最大的问题 ...
- javascript创建对象之原型模式(三)
少废话,先上代码: function Human() { } Human.prototype.name = "成吉思汗"; Human.prototype.sex = " ...
- javascript创建对象之函数构造模式和原型模式结合使用(四)
创建自定义类型的常见方式就是组合使用构造函数模式与原型模式一起使用. 构造函数模式用于定义实例对象的特有的部分(属性和方法),原型模式用于定义共享的部分. 这样最大限度的节省了内存的开销. funct ...
- [19/04/24-星期三] GOF23_创建型模式(建造者模式、原型模式)
一.建造者模式 本质:分离了对象子组件的单独构造(由Builder负责)和装配的分离(由Director负责),从而可以构建出复杂的对象,这个模式适用于:某个对象的构建过程十分复杂 好处:由于构建和装 ...
- Java进阶篇设计模式之三 ----- 建造者模式和原型模式
前言 在上一篇中我们学习了工厂模式,介绍了简单工厂模式.工厂方法和抽象工厂模式.本篇则介绍设计模式中属于创建型模式的建造者模式和原型模式. 建造者模式 简介 建造者模式是属于创建型模式.建造者模式使用 ...
随机推荐
- cf702C Cellular Network
C. Cellular Network time limit per test 3 seconds memory limit per test 256 megabytes input standard ...
- linux新内核中关闭硬盘的DMA
vortex86 SIS550 Minit-5250E瘦客户机,使用CF卡启动,显示不支持DMA. 搜索得新内核已基本不再使用ide=nodma参数了,查到这篇文章:“Debian下关闭CF卡的DMA ...
- 继续畅通工程(kruskal prim)
kruskal算法 #include <cstdio > #include <algorithm> using namespace std; const int MaxSi ...
- hdu 4579 博弈+区间dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4597 #include <cstdio> #include <cstring> ...
- media screen 响应式布局(知识点)
一.什么是响应式布局? 响应式布局是Ethan Marcotte在2010年5月份提出的一个概念,简而言之,就是一个网站能够兼容多个终端--而不是为每个终端做一个特定的版本.这个概念是为解决移动互联网 ...
- cgdb调试postgresql
之前一直用gdb调试代码,最近在搞pg的时候用了一个cgdb,体验很好,调试pg代码的时候真的很方便. 本文主要讲解在进行pg内核开发的时候,如何搭建一个环境,用cgdb方便快捷的调试postgres ...
- 需要知道的开源的框架-IOS
1:SDWebImage,UIImageView+WebCache加载一张图片. 2:UIViewExt用于定位坐标很有用,可以直接拿到bottom,top,left,right. 转:http:// ...
- UVALIVE 4819 最大流
题意:有N场比赛,每场比赛需要一定数量的题目数,现在有M个题目,每个题目只能提供给特定的几场比赛,并且一次只能在一场比赛中出现. 问最多可以举办多少场比赛. 思路:因为N = 15 , 所以直接二进制 ...
- 由阿里巴巴一道笔试题看Java静态代码块、静态函数、动态代码块、构造函数等的执行顺序
一.阿里巴巴笔试题: public class Test { public static int k = 0; public static Test t1 = new Test("t1&qu ...
- mysql批量删除指定前缀或后缀表
今天突然发现我们数据库中多出很多表,后缀名为"copy",预计是navicat直接拷贝导致的,然后要对这些有同样后缀名的表进行删除,假设一个一个选择会非常麻烦,表计较多,在网上找了 ...