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作用域下的,因此他指向全局变量 对象冒充: 实例属性不会共享!
随机推荐
- PowerDesigner成功生成PDM进行check model后的错误提示解决途径
1.existence of reference join------->缺少主键; 2.constraint name uniquesness-------->关联约束重名(refere ...
- ajax局部刷新后,如何让局部中的百度分享重新加载
我这个人不怎么喜欢说太多话,看几个图你们就懂了 Ajax前 Ajax之后 原因分析 解决方法 收工 百度分享是集成了众多主流第三方网站分享和收藏按钮的工具. 通过百度分享轻松将主流第三方网站的分享按钮 ...
- LINQ系列:Linq to Object集合操作符
集合操作符对元素的集合或序列集合进行操作,并返回一个集合.LINQ共有4种集合查询操作符:Distinct.Union.Intersect和Except. 1. Distinct Distinct操作 ...
- 让hammer完美支持Pixi.js - 2D webG库
由于项目改造,采用2D webG的pixi库,那么基于canvas的结构上,事件就是最大的一个问题了 改造的原理很简单,把hammer里面的addEventListeners事件绑定给第三方库代替,事 ...
- OpenCASCADE Make Primitives-Sphere
OpenCASCADE Make Primitives-Sphere eryar@163.com Abstract. The sphere is the simplest topology shape ...
- WPF做验证码,小部分修改原作者内容
原文地址:http://www.cnblogs.com/tianguook/p/4142346.html 首先感谢aparche大牛的帖子,因为过两天可能要做个登录的页面,因此,需要用到验证码,从而看 ...
- 页面loading效果
当网页太大,打开太慢的时候,为了增加良好的用户体验(不让用户眼巴巴的等,心中暗骂c,这么慢),我们需要加一个等待动画. 只需把以下代码加入页面中即可,图片可以根据自己的需求更换,更换图片之后需要改变l ...
- 分享几个.NET WinForm开源组件,纪念逐渐远去的WinForm。。。
前面3个月的时间内,这些.NET开源项目你知道吗?系列文章已经发表了3篇,共计45个平时接触比较少,曾经默默无闻的.NET开源项目,展示给大家,当然不是每个人都能用得上,但也的确是有些人用了,反响还不 ...
- Windows Server 2008 R2 WEB服务器配置系列文章索引
最近这段时间趁天翼云1元主机活动,购买了一个1元主机,主要是为了写一些服务器配置的教程. 已经完成如下几篇文章,送给大家. 国内云主机比较 天翼云/阿里云/腾讯云 Windows Server 200 ...
- T-Sql(二)事务(Transaction)
今天讲下T-Sql语法中事务的用法,事务在项目中一般用的很少,主要用于转账,或是一些多表操作,第一步完成不了滚回,不执行接下的步骤.要么都不完成要么都完成,这是事务的特征. 语法很简单,示例代码如下: ...