JavaScript面向对象与原型
工厂模式:无法识别对象
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面向对象与原型的更多相关文章
- 第一百零九节,JavaScript面向对象与原型
JavaScript面向对象与原型 学习要点: 1.学习条件 2.创建对象 3.原型 4.继承 ECMAScript有两种开发模式:1.函数式(过程化),2.面向对象(OOP).面向对象的语言有一个标 ...
- 有关javaScript面向对象和原型笔记
javaScript是一种比較特殊的语言,ECMAScript中没有类的概念.跟其它面向对象的语言有一定的差别.它的对象也与基于类的语言中的对象有所不同,严格来说,javascript对象是一组没有特 ...
- 了解JavaScript 面向对象基础 & 原型与对象
面向对象语言中的对象 老是能听到什么基于对象, 面向对象. 什么是对象, 如果有面向对象基础的人可以无视了, 下面举个简单的例子给大家讲讲面向对象中, 对象的定义, 这个是比较通用的, 不过对于JS来 ...
- JavaScript面向对象和原型函数
对象,是javascript中非常重要的一个梗,是否能透彻的理解它直接关系到你对整个javascript体系的基础理解,说白了,javascript就是一群对象在搅..(哔!). 常用的几种对象创建模 ...
- JavaScript 面向对象与原型
ECMAScript有两种开发模式:1.函数式(过程化);2.面向对象(OOP); 一 创建对象1.普通的创建对象 ? 1 2 3 4 5 6 7 8 9 // 创建一个对象,然后给这个对象新的属性和 ...
- javascript面向对象和原型
/* //工厂模式 function createObject(name,age){ var obj = new Object();//新建一个对象 obj.name=name;//新建对象的属性 o ...
- 快速理解JavaScript面向对象编程—原型
总的来说js语言就是门面向对象编程的语言,对象这个概念几乎贯穿了整个js的学习. 对象 创建对象两种方法:(若要生成对象实例必须调用构造函数) 1.var obj = {name:"jer& ...
- JavaScript 面向对象之原型对象
原型的概述 我们创建的每个函数都有一个 prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法. 逻辑上可以这么理解:prototype 通过调用构 ...
- JavaScript——面向对象与原型
在最外面使用this,此时this是window作用域下的,因此他指向全局变量 对象冒充: 实例属性不会共享!
随机推荐
- A Simple OpenGL Shader Example II
A Simple OpenGL Shader Example II eryar@163.com Abstract. The OpenGL Shading Language syntax comes f ...
- .Net 转战 Android 4.4 日常笔记(8)--常见事件响应及实现方式
在Andrioid开发中,常见的事件如下 单击事件 OnClickListener 长按事件 OnLongClickListener 滑动事件 OnTouchListenner 键盘事件 OnKeyL ...
- floating IP 原理分析 - 每天5分钟玩转 OpenStack(107)
上一节我们通过 Web UI 创建为 cirros-vm3 分配了浮动 IP,今天将分析其工作原理. 首先查看 router 的 interface 配置: 可以看到,floating IP 已经配置 ...
- javascript中异步和闭包产生的困惑
这里我不打算大谈特谈什么是异步,什么是闭包,这些内容在博客园都已经写的够多的了,但是这些内容出现的多,并不代表所有初学者都已经撑握了,所以我还是打算,用一个比较常见的示例来分析一下,或许能让对这个问题 ...
- Windows 使用 Yeoman generators 创建 ASP.NET 应用程序
上一篇:<Windows 搭建 .NET 跨平台环境并运行应用程序> 阅读目录: Install Node.js Install yeoman-generators Create ASP. ...
- spring控制并发数的工具类ConcurrencyThrottleSupport和ConcurrencyThrottleInterceptor
官方文档: /** * Support class for throttling concurrent access to a specific resource. * * <p>Desi ...
- js 中类似时钟的显示
先上代码 <!DOCTYPE html> <html> <head> <script> function startTime() { var today ...
- 相克军_Oracle体系_随堂笔记015-网络原理及配置
oracle网络没有负载, 没有负载的就不容易出问题.相对很简单的. 1.监听的动态注册: PMON 注册监听,或者 alter system register; 强制PMON抓紧注册. 都属于动 ...
- supervisor 安装、配置、常用命令
前言 在 web 应用部署到线上后,需要保证应用一直处于运行状态,在遇到程序异常.报错等情况,导致 web 应用终止时,需要保证程序可以立刻重启,继续提供服务. 所以,就需要一个工具,时刻监控 web ...
- VS2013预览版安装 体验截图
支持与msdn帐号链接: 不一样的团队管理: 新建项目: