【JavaScript】 JS面向对象的模式与实践 (重点整治原型这个熊孩子 (/= _ =)/~┴┴ )
参考书籍
JS创建对象
一.构造函数模式创建对象
/**
* description: 构造函数模式创建对象
*/
function Type (p) {
this.param = p; // 定义属性
this.method = function () { // 定义方法
return this.param;
}
}
var obj1 = new Type(1); // {param:1, method: function(){...}}
var obj2 = new Type(2); // {param:2, method: function(){...}}
console.log(obj1.method()) // 输出1
console.log(obj2.method()) // 输出2
var obj = new Object;
obj.param = p;
obj.method = function () { ... };
二.原型模式创建对象
构造函数的缺陷与加入原型的原因
var obj1 = new Type(1); // {param:1, method: function(){...}}
var obj2 = new Type(2); // {param:2, method: function(){...}}
this.method = function () { // 定义方法
return this.param;
}
构造函数和原型的关系
- 一部分是不同对象各自独有的属性, 例如上文中的param. 在需求上,我们希望不同的对象拥有不同的param
- 一部分是不同对象间共享的属性, 例如上文中的method方法,在需求上,我们希望不同的对象共同使用同一个method。
function Type (p) {
this.param = p; // 定义属性
this.method = function () { // 定义方法
return this.param;
}
}
function Type (p) {
this.param = p; // 不同对象各自独有的属性
}
Type.prototype.method = function () { // 不同对象共享的属性
return this.param;
}
原型能是个普通对象吗?(反向探究原型的工作机制)
function Type (p) {
this.param = p; // 不同对象各自独有的属性
}
Type.prototype.method = function () { // 不同对象共享的属性
return this.param;
}
// 卧槽,卧槽! 要是这么麻烦我干脆别用原型了
var obj = new Type(1);
// 超级麻烦!
console.log(Object.getPrototypeOf(obj).method.call(obj)) // 输出1
// 也很麻烦!同时这种简化破环了我们面向对象的初衷
console.log(Type.prototype.method.call(obj)) //输出1
原型的工作机制
function Type (p) {
this.param = p; // 不同对象各自独有的属性
}
Type.prototype.method = function () { // 不同对象共享的属性
return this.param;
}
var obj = new Type(1);
console.log(obj);
obj.method();
function Type () {
this.a = '实例对象中的a';
}
Type.prototype.a = 'prototype中的a';
Type.prototype.b = 'prototype中的b';
var obj = new Type();
console.log(obj); //输出 : {a: "实例对象中的a"}
console.log(obj.a); //输出:实例对象中的a
console.log(obj.b); //输出: prototype中的b
function Type () {}
Type.prototype.str = '字符串'
Type.prototype.num = 1;
Type.prototype.arr = [1,2,3];
var obj = new Type();
console.log(obj); // {}
obj.str = '覆盖后字符串';
obj.num = 2;
obj.arr = [3,4,5];
console.log(obj.str); // 覆盖后字符串
console.log(obj.num); //
console.log(obj.arr); // [3.4.5]
console.log(Type.prototype.str); // 字符串
console.log(Type.prototype.num); //
console.log(Type.prototype.arr); // [1, 2, 3]
function Type () {}
Type.prototype.str = '字符串'
Type.prototype.num = 1;
var obj = new Type();
console.log(obj); // 空实例对象 {}
obj.str +=',加点东西'; // 尝试直接修改属性
obj.num += 1; // 尝试直接修改属性
console.log(obj.str); // 字符串,加点东西
console.log(obj.num); //
console.log(Type.prototype.str); // 字符串
console.log(Type.prototype.num); // 1
console.log(obj); // {str: "字符串,加点东西", num: 2}
- 在实例中没有该属性时,直接修改基本类型的实例属性等同于为其添加属性,而且添加的属性值是在原型对象属性值的基础上进行的
- 在直接修改基本类型的实例属性时, 原型对象中的属性仍然没有变化! 这进一步证明了原型对象中的数据具有一定的“稳定性”

function Type () {}
Type.prototype.objProperty = {a: 1};
Type.prototype.arrProperty = [1,2];
var obj = new Type();
console.log(obj.objProperty) // {a: 1}
console.log(obj.arrProperty) // [1, 2]
obj.objProperty.a = 111; // 直接修改引用类型的属性值
obj.arrProperty.push(3); // 直接修改引用类型的属性值
// 原型对象中的属性值被修改了
console.log(Type.prototype.objProperty) // {a: 111}
console.log(Type.prototype.arrProperty) // [1, 2, 3]
console.log(obj); // 输出 {} obj还是空的!!
原型在OO体系中暴露的缺陷
function Type () {}
Type.prototype.arrProperty = [1,2];
var obj1 = new Type();
var obj2 = new Type();
console.log(obj2.arrProperty) // [1, 2]
obj1.arrProperty.push(3);
console.log(obj2.arrProperty); // [1, 2, 3] 我怎么被修改了???
对原型模式的评价
三.组合模式创建对象
function Person (name, age) {
this.name = name;
this.age = age;
this.friends = ['Wang','Li'];
}
Person.prototype.sayName = function () {
return this.name;
}
var person1 = new Person('Zhang',13);
var person2 = new Person('Huang',15);
person1.friends.push('Peng')
console.log(person1.friends); // ["Wang", "Li", "Peng"]
console.log(person2.friends); // ["Wang", "Li"]
console.log(person1.sayName()) // Zhang
console.log(person2.sayName()) // Huang
console.log(person1.sayName == person2.sayName) // true
JS中的继承
一.借用构造函数实现继承
/**
* description: 借用构造函数实现继承
*/
function superType () { // "父类"构造函数
this.name = "aaa";
this.sayName = function () {
return this.name
}
}
function subType () { // "子类"构造函数
superType.call(this); // 调用“父类“的构造函数
}
var obj = new subType();
console.log(obj.name); // 输出 aaa
console.log(obj.sayName()); // 输出 aaa
function superType (name) { // "父类"构造函数
this.name = name;
this.sayName = function () {
return this.name
}
}
function subType (name) { // "子类"构造函数
superType.call(this,name); // 调用“父类“的构造函数,并传递参数
}
var obj = new subType("XXX")
console.log(obj.name); // 输出XXX
console.log(obj.sayName()); // 输出XXX
二.利用原型和原型链实现继承
/**
* description: 利用原型和原型链实现继承
*/
function superType () { // "父类"构造函数
this.name = 'XXX'
}
superType.prototype.sayName = function () {
return this.name;
}
function subType () { } // "子类"构造函数
// 创建父类构造函数的实例,并赋给子类的原型
subType.prototype = new superType();
var obj = new subType();
console.log(obj.sayName()); // 输出 XXX
subType.prototype = new superType(); // {name: "XXX"}
subType.prototype = new superType();// #1
var obj = new subType(); // #2
原型链下属性的搜索机制
仅仅使用原型链实现继承的缺点
function superType () { // "父类"构造函数
this.arr = [1,2]
}
function subType () { } // "子类"构造函数
subType.prototype = new superType();
var obj1 = new subType();
var obj2 = new subType();
console.log(obj2.arr); // 输出 [1, 2]
obj1.arr.push(3);
console.log(obj2.arr); // 输出 [1, 2, 3] 卧槽,我又被乱改了!
三.组合继承
/**
* description: 组合继承的例子
*/
function SuperType (name) {
this.name = name;
this.colors = ['red','blue','green'];
}
SuperType.prototype.sayName = function () {
console.log(this.name)
}
function SubType(name, age) {
SuperType.call(this,name); // 继承实例属性
this.age = age;
}
SubType.prototype = new SuperType(); // 继承方法
SubType.prototype.sayAge = function () { // 写入新的方法
console.log(this.age)
}
var obj1 = new SubType('Wang', 20);
obj1.colors.push('black');
console.log(obj1.colors); // ["red", "blue", "green", "black"]
obj1.sayName(); // Wang
obj1.sayAge(); //
var obj2 = new SubType('Zhang', 23);
console.log(obj2.colors); // ["red", "blue", "green"]
obj2.sayName(); // Zhang
obj2.sayAge(); //
面向对象中的原型——OO体系和OLOO体系的碰撞和融合
OO设计模式
class Vehicle {
setColor (color) { this.color = color }
setWheels (num) { this.wheels = num }
setEngine (num) { this.engine = num }
}
class Car extends Vehicle { // 继承
setWheels () { this.wheels = 4 } // 方法重写
setEngine (1) { this.engine = 1 } // 方法重写
}
如图

OLOO设计模式
// 工具对象
VehicleParts = {
setWheels: function (num) { ... } // 安装车轮
setEngine: function (num) { ... } // 安装引擎
}
// 衍生对象
Car.protoType = VehicleParts; // 委托
Car.build = function () {
setWheels(4); // 4轮子
setEngine(1); // 1引擎
}
Bike.protoType = VehicleParts; // 委托
Bike.build = function () {
setWheels(2); // 2轮子
setEngine(0); // 0引擎
}
如图

对原型恰当的认知方式

【JavaScript】 JS面向对象的模式与实践 (重点整治原型这个熊孩子 (/= _ =)/~┴┴ )的更多相关文章
- JavaScript (JS) 面向对象编程 浅析 (含对象、函数原型链、闭包解析)
1. 构造函数原型对象:prototype ① 构造函数独立创建对象,消耗性能 function Person(name) { this.name = name; this.sayHello = fu ...
- JavaScript---正则使用,日期Date的使用,Math的使用,JS面向对象(工厂模式,元模型创建对象,Object添加方法)
JavaScript---正则使用,日期Date的使用,Math的使用,JS面向对象(工厂模式,元模型创建对象,Object添加方法) 一丶正则的用法 创建正则对象: 方式一: var reg=new ...
- javascript类式继承模式#3——借用和设置原型
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- javascript(js)创建对象的模式与继承的几种方式
1.js创建对象的几种方式 工厂模式 为什么会产生工厂模式,原因是使用同一个接口创建很多对象,会产生大量的重复代码,为了解决这个问题,产生了工厂模式. function createPerson(na ...
- 读《深入PHP 面向对象、模式与实践》笔记
1. include() 和require() 语句的不同在于它们如何处理错误.使用require()调用文件发生错误时,将会停止整个程序;调用include()时遇到相同的错误,则会生成警告并停止执 ...
- 读《深入php面向对象、模式与实践》有感(三)
命令模式: 第一次接触到这个命令模式的时候,感觉它很像一个简化的mvc框架.从不同的路径访问,再由控制器来判断所要调用的具体php文件. <?php class CommandContext{ ...
- 读《深入php面向对象、模式与实践》有感(二)
书中关于设计模式的介绍很详细. 一.单例模式 作者建了一个preferences类来解释什么是单例模式.这个preferences类并非我第一次见到,在android中也有这个类,不过以前都是只管用即 ...
- 《深入PHP:面向对象、模式与实践》(二)
第4章 高级特性 本章内容提要: 静态属性和方法:通过类而不是对象来访问数据和功能 抽象类和接口:设计和实现分离 错误处理:异常 Final类和方法:限制继承 拦截器方法:自动委托 析构方法:对象销毁 ...
- 《深入PHP:面向对象、模式与实践》(一)
第1章 PHP:设计与管理 本章主要介绍了本书有哪些内容. 第2章 PHP与对象 本章总结了PHP面向对象特性的发展过程,逐步介绍对象的概念. PHP/FI:支持变量.关联数组和函数.没有对象. ...
随机推荐
- SimpleMembership续
自上篇SimpleMembership之后,好久不用,也没有研究,最近把以前写的老程序改进下,原有用户系统升级为SimpleMembership,在升级的过程中发现还有许多问题,经过几天的试验,小有收 ...
- Spring MVC体系结构和处理请求控制器
Spring MVC体系结构和处理请求控制器 一:MVC设计模式: (1.)数据访问接口:DAO层 (2.)处理业务逻辑层:Service层 (3.)数据实体:POJO (4.)负责前段请求接受并处理 ...
- 使用 Rust 构建分布式 Key-Value Store
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 引子 构建一个分布式 Key-Value Store 并不是一件容易的事情,我们需要考虑很多的问题,首先就是我们的系统到底需要提供什么样的功能 ...
- Drools文档(六) 用户手册
用户手册 基础 无状态的知识Session Drools规则引擎拥有大量的用例和功能,我们要如何开始?你无须担心,这些复杂性是分层的,你可以用简单的用例来逐步入门. 无状态Session,无须使用推理 ...
- java 中 “文件” 和 “流” 的简单分析
java 中 FIle 和 流的简单分析 File类 简单File 常用方法 创建一个File 对象,检验文件是否存在,若不存在就创建,然后对File的类的这部分操作进行演示,如文件的名称.大小等 / ...
- 查看Page结构
SQL Server存储数据的基本单元是Page,每一个Page的大小是8KB,数据文件是由Page构成的.在同一个数据库上,每一个Page都有一个唯一的资源标识,标识符由三部分组成:db_id,fi ...
- linux正确的关机方法
[root@localhost ~]# sync #数据写入磁盘 [root@localhost ~]# shutdown -h 10 #通知用户再过10分钟就关机 [root@localhost ~ ...
- 一个非常好用的图片切割工具(c# winform开发) 附源码
本人业余时间开发了一个图片切割工具,非常好用,也很灵活! 特别对大型图片切割,更能体现出该软件的优势! 开发工具为winform,源码下载地址:http://download.csdn.net/dow ...
- 【jQuery插件】使用cropper实现简单的头像裁剪并上传
插件介绍 这是一个我在写以前的项目的途中发现的一个国人写的jQuery图像裁剪插件,当时想实现用户资料的头像上传功能,并且能够预览图片,和对图片进行简单的裁剪.旋转,花了不少时间才看到了这个插件,感觉 ...
- Python中的冒泡排序
冒泡排序 冒泡排序(英语:Bubble Sort)是一种简单的排序算法.它重复地遍历要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来.遍历数列的工作是重复地进行直到没有再需要交换,也 ...