Js原型模式
function Person(){
}
Person.prototype.name = "xd";
Person.prototype.age = 26;
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
person1.sayName();//"xd"
var person2 = new Person();
person2.sayName();//"xd"
alert(person1.sayName==person2.sayName);//true
代码讲解:
第一个函数,可以称其为构造函数,在js中函数就是对象,因此每定义一个函数就相当于创建了一个对象,这里我们相当于创建了一个名为Person的对象。
2-3行中有一个prototype(原型)属性,这个属性是一个指针,指向要被“new”的对象,即原型对象。将对象的属性都添加到原型对象中。
为什么要用到原型模式来创建对象那?
先来介绍比较常见的两种创建对象的方法:
第一种,工厂模式
示例代码如下:
function createPerson(name,age,job)
{
var o = new Object();
o.name = name;
o.age = age;
o.job = job;
o.sayName = function(){
alert(this.name);
}
return o;
}
var person1 = createPerson("a",,"aa");
var person2 = createPerson("b",,"bb");
工厂模式创建对象的方法是,在方法中创建一个Object类,然后对这个实例的属性赋值,最后返回这个Object实例。通过调用这个方法,就可以获得一个期望的对象。但是这个方法有一个缺陷,就是无法知道你所创建对象的类型。
第二种,构造函数模式
示例代码如下:
function Person(name,age,job)
{
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
var person1 = new Person("a",,"aa");
var person2 = new Person("b",),"bb";
alert(person1.constructor==Person);//true
alert(person1 instanceof Object);//true
alert(person1 instanceof Person);//true
"this"指向的是你"new"的对象。
person1和person2分都有一个constructor(构造函数)属性,该属性指向Person。
任何函数,只要通过new操作来调用,那它就可当做构造函数,如果不用new来调用,那它和普通函数没有区别。
例如:
//当做构造函数来使用
var person = new Person("a",,"aa");
person.sayName();
//当做普通函数来调用
Person("a",,"aa");//这里this指向了window对象,即以window对象作为原型。
window.sayName();
//在另一个对象的作用域中来用。
var o = new Object();
Person.call(o,"a",,"aa");//这里把o对象作为原型,this指向了对象o。(这里的call也可以换为apply)
o.sayName();
构造函数创建实例的缺点:
每个构造函数在用于创建实例时,其中的方法都要重新创建一遍。person1和person2中的sayName()方法不是同一个Function实例。
解决方法如下:
function Person(name,age,job)
{
this.name = name;
...
this.sayName = sayName;
}
function sayName()
{
alert(this.name);
}
...
这里sayName属性保存的是指向函数sayName()的指针,解决了上述问题。
新问题:这里定义的在全局域定义的函数只能被某个对象调用,作为全局作用域有点...
其次,如果构造函数中有很多方法,就要定义很多全局函数,就没有丝毫封装性可言。
所以最终我们选用了原型模式。
原型对象的问:
问题1:它省略了构造函数初始化参数这一环节,结果所有的实例在默认的情况下都将取得相同的属性值。
问题2:原型中所有的属性都是共享的,这种共享对于函数很合适,但对于包含引用类型的属性来说,就会出现问题。
例如:
function Person()
{}
Person.prototype = {
constructor:Person,
name:"a",
job:"b",
friends:["c","d"],
sayName(){
alert(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("e");
alert(person1.friends);//"c","d","e"
alert(person2.friends);//"c","d","e"
alert(person1.friends===person2.friends);//true
从上边的代码可以看出本来person1与person2中的friends是不应该相同的,结果由于将属性friends属性放在了原型对象中,导致期所有的实例的所有属性都相同了。
解决办法就是组合使用构造函数模式和原型模式。
构造函数模式用于定义实例属性。
原型模式用于定义方法和共享属性。
最终每个实例都有自己的一份实例属性的副本,但同时又共享了对方法的引用。
例如:
function Person(name,age,job)
{
this.name = name;
this.age = age;
this.job = job;
this.friends = ["a","b"];
}
Person.prototype = {
constructor:Person,
sayName = function(){
alert(this.name);
}
}
动态原型模式:
如果大家觉得将一个对象分成两个方法来写有点别扭,那么可以用动态原型模式来书写。
代码如下:
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.friends = ["a","b"];
if(typeof this.sayName!="function")
{
Person.prototype.sayName = function(){
alert(this.name);
}
}
}
var person1 = new Person("a","b","c");
person1.sayName();
var person2 = new Person("e","f","g");
person2.sayName();
上边代码只有在第一次实例化时才初始化原型属性,而且判定条件只需要原型中的一个属性即可。
注意:不可以在动态原型模式中使用对象字面量来重写原型。
Js原型模式的更多相关文章
- JS --- 原型模式
创建一个对象,先来看一段代码: // 例如创建一个 Person 的构造函数, 让人有名字, 可以说话 function Person ( name ) { this.name = name; // ...
- js原型模式和继承
function SuperType() { this.property = true; //原型属性 } //基类方法 SuperType.prototype.getSuperValue = fun ...
- JS中prototype属性-JS原型模式
/* *对象方法 *类方法 * 原型方法 */ function People(name) { this.name = name; this.say = function () { //对象方法 al ...
- JS 原型模式创建对象
例子: class Test { constructor(val) { this.val = val } walk() { console.log(this) console.log('walk') ...
- js设计模式:工厂模式、构造函数模式、原型模式、混合模式
一.js面向对象程序 var o1 = new Object(); o1.name = "宾宾"; o1.sex = "男"; o1.a ...
- 面向对象JS基础讲解,工厂模式、构造函数模式、原型模式、混合模式、动态原型模式
什么是面向对象?面向对象是一种思想!(废话). 面向对象可以把程序中的关键模块都视为对象,而模块拥有属性及方法.这样我们如果把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作.接下 ...
- 关于js的对象创建方法(简单工厂模式,构造函数模式,原型模式,混合模式,动态模式)
// 1.工厂方式创建对象:面向对象中的封装函数(内置对象) 简单来说就是封装后的代码,简单的工厂模式是很好理解的,关于它的作用,就是利用面向对象的方法,把一些对象封装,使一些占用空间多的,重复的代码 ...
- JS面向对象基础讲解(工厂模式、构造函数模式、原型模式、混合模式、动态原型模式)
什么是面向对象?面向对象是一种思想. 面向对象可以把程序中的关键模块都视为对象, 而模块拥有属性及方法. 这样如果我们把一些属性及方法封装起来,日后使用将非常方便,也可以避免繁琐重复的工作. 工厂 ...
- JS面向对象(1)——构造函数模式和原型模式
1.构造函数模式 构造函数用来创建特定的类型的对象.如下所示: function Person(name,age,job){ this.name=name; this.job=job; this.ag ...
随机推荐
- unity3d GameObject.Find 严格区分大小写的
GameObject.Find 查找 static function Find (name : string) : GameObject Description描述 Finds a game obje ...
- HDU2594 Simpsons’ Hidden Talents 字符串哈希
最近在学习字符串的知识,在字符串上我跟大一的时候是没什么区别的,所以恶补了很多基础的算法,今天补了一下字符串哈希,看的是大一新生的课件学的,以前觉得字符串哈希无非就是跟普通的哈希没什么区别,倒也没觉得 ...
- hdu 3758 Factorial Simplification
这题主要是质因数分解!! 求出每个因子的幂,如果有负数,则输出-1: 如果2的幂数为0,这输出0: 最后就是开始凑阶乘了…… #include<iostream> #include< ...
- Servlet 各种path路径比较
假定你的web application 名称为news,你在浏览器中输入请求路径: http://localhost:8080/news/main/list.jsp 则执行下面向行代码后打印出如下结果 ...
- mysql InnoDB 索引小记
0.索引结构 1).MyISAM与InnoDB索引结构比较,如下: 2).MyISAM的索引结构 主键索引和二级索引结构很像,叶子存储的都是索引以及数据存储的物理地址,其他节点存储的仅仅是索引信息.其 ...
- lintcode : 二叉树的层次遍历
题目 二叉树的层次遍历 给出一棵二叉树,返回其节点值的层次遍历(逐层从左往右访问) 样例 给一棵二叉树 {3,9,20,#,#,15,7} : 3 / \ 9 20 / \ 15 7 返回他的分层遍历 ...
- java代码实现自动登录功能
通常我们登录某网站,会有选择保存几天,或者是几个星期不用登录,之后输入该网站地址无需登录直接进入主页面,那么这就叫做自动登录,怎么实现呢,下面我以一个小例子来演示一下 登录页面:login.jsp & ...
- HTML5入门4---HTML5 与 HTML4 同一网页的不同写法
HTML4写法 css: body { font-family: "Lucida Sans Unicode", "Lucida Grande", Verdana ...
- Linux中断处理体系结构分析
Linux中断处理体系结构分析(一) 异常,就是可以打断CPU正常运行流程的一些事情,比如外部中断.未定义指令.试图修改只读的数据.执行swi指令(Software Interrupt Instruc ...
- 获取其他进程中ListBox和ComboBox的内容
(*// 标题:获取其他进程中ListBox和ComboBox的内容 说明:Window2000+Delphi6调试通过 设计:Zswang 支持:wjhu111@21cn.com 日期:2004-0 ...