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作用域下的,因此他指向全局变量 对象冒充: 实例属性不会共享!
随机推荐
- SpringMVC配置项学习笔记
1. <mvc:annotation-driven /> <mvc:annotation-driven />是一种简写形式,默认会注册DefaultAnnotationHand ...
- SpringMVC常用的注解
1. @Controller @Controller用于标识控制层主键,负责注册一个bean到spring上下文,bean的ID默认为首字母小写的类名称,用户也可以自定义. 例如: 方式一: @Co ...
- springboot学习笔记(一)
一.什么是SpringBoot 描述:Spring Boot是Spring社区发布的一个开源项目,旨在帮助开发者快速并且更简单的构建项目.大多数SpringBoot项目只需要很少的配置文件.二.Spr ...
- Javascript学习记录——原生JS实现旋转木马特效
昨天学习到了JS特效部分,然后老师讲了旋转木马特效的实现,如上图.不过只是讲了通过点击箭头实现图片的切换,对于点击图片本身以及二者联动却是没有讲解. 本着一颗追求完美的心,今天花费了一个中午终于将整个 ...
- C++类的静态成员详解
类的静态成员分为静态数据成员和静态成员函数 静态数据成员 假如我们要设计一个战争游戏,游戏中有许多的兵种.游戏的过程中,每隔一段时间每个兵种都会产生,同时由于战争的消耗,每个兵种士兵的数量又会减少.为 ...
- 深入理解CSS Media媒体查询
× 目录 [1]媒介类型 [2]媒体属性 [3]语法[4]方法 前面的话 一说到响应式设计,肯定离不开媒体查询media.一般认为媒体查询是CSS3的新增内容,实际上CSS2已经存在了,CSS3新增了 ...
- SpringMVC+FreeMarker
前言: 最近在学习SpringMVC,模板引擎用的是FreeMarker,之前没有接触过.利用SpringMVC开发其实还有许多的步骤,比如控制层,服务层,持久化层,实体等等,先弄了一个小demo来总 ...
- T-SQL:毕业生出门需知系列(三)
第3课 排序检索数据 3.1 排序数据(ORDER BY) 下面的 SQL 语句返回某个数据库表的单个列.观察其输出,并没有特定的顺序. SELECT prod_name FROM Products; ...
- C++ 与 php 的交互 之----- C++ 获取 网页文字内容,获取 php 的 echo 值。
转载请声明出处! http://www.cnblogs.com/linguanh/category/633252.html 距离上次 谈 C++ 制作json 或者其他数据传送给 服务器,时隔两个多月 ...
- js 对闭包的理解
<!DOCTYPE html> <html> <body> <p>局部变量计数.</p> <button type="but ...