工厂模式:无法识别对象

function createObject(name, age) { //集中实例化的函数
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.run = function () {
    return this.name + this.age + '运行中...';
  };
  return obj;
}
var box1 = createObject('Lee', 100); //第一个实例
var box2 = createObject('Jack', 200); //第二个实例
alert(box1.run());
alert(box2.run()); //保持独立

alert(typeof box1); //Object
alert(box1 instanceof Object); //true

构造函数(构造方法):可以识别对象

function Box(name, age) { //构造函数模式
  this.name = name;
  this.age = age;
  this.run = function () {
    return this.name + this.age + '运行中...';
  };
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);

alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于 Box

构造函数的方法有一些规范:

1.函数名和实例化构造名相同且大写,(PS:非强制,但这么写有助于区分构造函数和普通函数);

2.通过构造函数创建对象,必须使用 new 运算符。

var o = new Object();
Box.call(o, 'Jack', 200) //对象冒充调用
alert(o.run());

原型(共享):创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上可以这么理解:prototype 通过调用构造函数而创建的那个对象的原型对象。使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以直接将这些信息添加到原型中。

unction Box() {} //声明一个构造函数
Box.prototype.name = 'Lee'; //在原型里添加属性
Box.prototype.age = 100;
Box.prototype.run = function () { //在原型里添加方法
  return this.name + this.age + '运行中...';
};

在原型模式声明中,多了两个属性,这两个属性都是创建对象时自动生成的。

__proto__属性:是实例指向原型对象的一个指针,它的作用就是指向构造函数的原型属性 constructor 。通过这两个属性,就可以访问到原型里的属性和方法了。

PS:IE 浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。

判断一个对象是否指向了该构造函数的原型对象,可以使用 isPrototypeOf()方法来测试。

exp:alert(Box.prototype.isPrototypeOf(box)); //只要实例化对象,即都会指向

原型模式的执行流程:
1.先查找构造函数实例里的属性或方法,如果有,立刻返回;
2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;

虽然我们可以通过对象实例访问保存在原型中的值,但却不能访问通过对象实例重写原型中的值。

var box1 = new Box();
alert(box1.name); //Lee,原型里的值
box1.name = 'Jack';
alert(box.1name); //Jack,就近原则,
var box2 = new Box();
alert(box2.name); //Lee,原型里的值,没有被 box1 修改
如果想要 box1 也能在后面继续访问到原型里的值,可以把构造函数里的属性删除即可 ,具体如下:
delete box1.name; //删除属性
alert(box1.name);
如何判断属性是在构造函数的实例里,还是在原型里?可以使用 hasOwnProperty()函数来验证:

alert(box.hasOwnProperty('name')); //实例里有返回 true,否则返回 false

in 操作符会在通过对象能够访问给定属性时返回 true,无论该属性存在于实例中还是原型中。
alert('name' in box); //true,存在实例中或原型中
我们可以通过 hasOwnProperty()方法检测属性是否存在实例中,也可以通过 in 来判断实例或原型中是否存在属性。那么结合这两种方法,可以判断原型中是否存在属性。

function isProperty(object, property) { //判断原型中是否存在属性
  return !object.hasOwnProperty(property) && (property in object);
}

var box = new Box();
alert(isProperty(box, 'name')) //true,如果原型有

为了让属性和方法更好的体现封装的效果,并且减少不必要的输入,原型的创建可以使用字面量的方式:

function Box() {};
Box.prototype = { //使用字面量的方式
  name : 'Lee',
  age : 100,
  run : function () {
    return this.name + this.age + '运行中...';
  }
};

使用构造函数创建原型对象和使用字面量创建对象在使用上基本相同,但还是有一些区别,字面量创建的方式使用 constructor 属性不会指向实例,而会指向 Object,构造函数创建的方式则相反。

如果想让字面量方式的 constructor 指向实例对象,那么可以这么做:
Box.prototype = {
  constructor : Box, //直接强制指向即可
};

原型对象不仅仅可以在自定义对象的情况下使用,而 ECMAScript 内置的引用类型都可以使用这种方式,并且内置的引用类型本身也使用了原型。

alert(Array.prototype.sort); //sort 就是 Array 类型的原型方法
alert(String.prototype.substring); //substring 就是 String 类型的原型方法
String.prototype.addstring = function () { //给 String 类型添加一个方法
  return this + ',被添加了!'; //this 代表调用的字符串
};
alert('Lee'.addstring()); //使用这个方法

PS:尽管给原生的内置引用类型添加方法使用起来特别方便,但我们不推荐使用这种方法。因为它可能会导致命名冲突,不利于代码维护。

动态原型模式

function Box(name ,age) { //将所有信息封装到函数体内
  this.name = name;
  this.age = age;
  if (typeof this.run != 'function') { //仅在第一次调用的初始化
    Box.prototype.run = function () {
      return this.name + this.age + '运行中...';
    };
  }
}
var box = new Box('Lee', 100);
alert(box.run());

PS:使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。

寄生构造函数

function Box(name, age) {
  var obj = new Object();
  obj.name = name;
  obj.age = age;
  obj.run = function () {
    return this.name + this.age + '运行中...';
  };
  return obj;
}

稳妥构造函数

function Box(name , age) {
  var obj = new Object();
  obj.run = function () {
    return name + age + '运行中...'; //直接打印参数即可
  };
  return obj;
}
var box = Box('Lee', 100); //直接调用函数
alert(box.run());

继承:依靠原型链完成

function Box() { //Box 构造
  this.name = 'Lee';
}
function Desk() { //Desk 构造
  this.age = 100;
}
Desk.prototype = new Box(); //Desc 继承了 Box,通过原型,形成链条
var desk = new Desk();
alert(desk.age);
alert(desk.name); //得到被继承的属性
function Table() { //Table 构造
  this.level = 'AAAAA';
}
Table.prototype = new Desk(); //继续原型链继承
var table = new Table();
alert(table.name); //继承了 Box 和 Desk

在 JavaScript 里,被继承的函数称为超类型(父类,基类也行,其他语言叫法),继承的函数称为子类型(子类,派生类)。继承也有之前问题,比如字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

对象冒充(伪造对象、经典继承、借用构造函数):解决引用共享和超类型无法传参的问题

function Box(age) {
  this.name = ['Lee', 'Jack', 'Hello']
  this.age = age;
}
function Desk(age) {
  Box.call(this, age); //对象冒充,给超类型传参

}
var desk = new Desk(200);
alert(desk.age);
alert(desk.name);
desk.name.push('AAA'); //添加的新数据,只给 desk
alert(desk.name);

组合继承:原型链+ 借用构造函数

function Box(age) {
  this.name = ['Lee', 'Jack', 'Hello']
  this.age = age;
}
Box.prototype.run = function () {
  return this.name + this.age;
};
function Desk(age) {
  Box.call(this, age); //对象冒充
}
Desk.prototype = new Box(); //原型链继承
var desk = new Desk(100);
alert(desk.run());

寄生组合继承

function obj(o) {     //传递一个字面量函数
  function F() {}    //临时新建一个构造函数,用来存储传递进来的对象
  F.prototype = o;    //将o对象实例赋值给F构造的原型对象

  return new F();    //返回实例化后的构造函数
}
function create(box, desk) {
  var f = obj(box.prototype);
  f.constructor = desk;
  desk.prototype = f;
}
function Box(name) {
  this.name = name;
  this.arr = ['哥哥','妹妹','父母'];
}
Box.prototype.run = function () {
  return this.name;
};
function Desk(name, age) {
  Box.call(this, name);
  this.age = age;
}
inPrototype(Box, Desk); //通过这里实现继承
var desk = new Desk('Lee',100);
desk.arr.push('姐姐');
alert(desk.arr);
alert(desk.run()); //只共享了方法
var desk2 = new Desk('Jack', 200);
alert(desk2.arr); //引用问题解决

JavaScript面向对象与原型的更多相关文章

  1. 第一百零九节,JavaScript面向对象与原型

    JavaScript面向对象与原型 学习要点: 1.学习条件 2.创建对象 3.原型 4.继承 ECMAScript有两种开发模式:1.函数式(过程化),2.面向对象(OOP).面向对象的语言有一个标 ...

  2. 有关javaScript面向对象和原型笔记

    javaScript是一种比較特殊的语言,ECMAScript中没有类的概念.跟其它面向对象的语言有一定的差别.它的对象也与基于类的语言中的对象有所不同,严格来说,javascript对象是一组没有特 ...

  3. 了解JavaScript 面向对象基础 & 原型与对象

    面向对象语言中的对象 老是能听到什么基于对象, 面向对象. 什么是对象, 如果有面向对象基础的人可以无视了, 下面举个简单的例子给大家讲讲面向对象中, 对象的定义, 这个是比较通用的, 不过对于JS来 ...

  4. JavaScript面向对象和原型函数

    对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅..(哔!). 常用的几种对象创建模 ...

  5. JavaScript 面向对象与原型

    ECMAScript有两种开发模式:1.函数式(过程化);2.面向对象(OOP); 一 创建对象1.普通的创建对象 ? 1 2 3 4 5 6 7 8 9 // 创建一个对象,然后给这个对象新的属性和 ...

  6. javascript面向对象和原型

    /* //工厂模式 function createObject(name,age){ var obj = new Object();//新建一个对象 obj.name=name;//新建对象的属性 o ...

  7. 快速理解JavaScript面向对象编程—原型

    总的来说js语言就是门面向对象编程的语言,对象这个概念几乎贯穿了整个js的学习. 对象 创建对象两种方法:(若要生成对象实例必须调用构造函数) 1.var obj = {name:"jer& ...

  8. JavaScript 面向对象之原型对象

    原型的概述 我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法. 逻辑上可以这么理解:prototype 通过调用构 ...

  9. JavaScript——面向对象与原型

    在最外面使用this,此时this是window作用域下的,因此他指向全局变量 对象冒充: 实例属性不会共享!

随机推荐

  1. Android笔记——提升ListView的运行效率

    之所以说 ListView 这个控件很难用,就是因为它有很多的细节可以优化,其中运行效率就是很重要的一点.目前我们ListView 的运行效率是很低的,因为在 FruitAdapter 的getVie ...

  2. 有关binlog的那点事(mysql5.7.13)

    binlog作为mysql中最重要的日志之一,能实现异常恢复以及主从复制. 我们主要讨论的是主从复制中的binlog,这里将以mysql5.7.13的源码为主要依据来分析binlog. 在主从复制中, ...

  3. 【原创】开源Math.NET基础数学类库使用(06)直接求解线性方程组

                   本博客所有文章分类的总目录:[总目录]本博客博文总目录-实时更新  开源Math.NET基础数学类库使用总目录:[目录]开源Math.NET基础数学类库使用总目录 前言 ...

  4. Openfire/XMPP学习之——Openfire的安装、配置

    一.Openfire下载: 官方下载:http://www.igniterealtime.org/downloads/index.jsp 在官方下载站点,可以获取Windows.Linux.Mac三种 ...

  5. C算法编程题系列

    我的编程开始(C) C算法编程题(一)扑克牌发牌 C算法编程题(二)正螺旋 C算法编程题(三)画表格 C算法编程题(四)上三角 C算法编程题(五)“E”的变换 C算法编程题(六)串的处理 C算法编程题 ...

  6. 使用Spire组件抛出异常The type initializer for 'spr857' threw an exception

    使用Spire组件抛出异常The type initializer for 'spr857' threw an exception 我使用免费的Spire.Xls组件尝试去转换Excel文档到PDF文 ...

  7. 深入seajs源码系列三

    入口方法 每个程序都有个入口方法,类似于c的main函数,seajs也不例外.系列一的demo在首页使用了seajs.use(),这便是入口方法.入口方法可以接受2个参数,第一个参数为模块名称,第二个 ...

  8. 四大组件之ContentProvider

    前言 ContentProvider作为Android的四大组件之一,是属于需要掌握的基础知识,可能在我们的应用中,对于Activity和Service这两个组件用的很常见,了解的也很多,但是对Con ...

  9. Hadoop NameNode的ZKFC机制

    博客原文:hackershell 之前在准备中级课程PPT,整理了下HA的基本内容,并且感谢松哥为我们提供了HA不会切的问题,以至于之后刚好出现的NameNode宕机,能够快速解决. NameNode ...

  10. git log命令全解析,打log还能这么随心所欲!

    git log命令非常强大而好用,在复杂系统的版本管理中扮演着重要的角色,但默认的git log命令显示出的东西实在太丑,不好好打扮一下根本没法见人,打扮好了用alias命令拍个照片,就正式出道了! ...