【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:支持变量.关联数组和函数.没有对象. ...
随机推荐
- python基础-------模块与包(二)
sys模块.logging模块.序列化 一.sys模块 sys.argv 命令行参数List,第一个元素是程序本身路径 sys.exit(n) 退出程序,正常退出时e ...
- netty 入门(一)
netty Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.更确切的讲是一个组件,没有那么复杂. 例子 一 Discard服务器端 我们 ...
- Java Web基础入门
前言 语言都是相通的,只要搞清楚概念后就可以编写代码了.而概念是需要学习成本的. Java基础 不用看<编程思想>,基础语法看 http://www.runoob.com/java/jav ...
- 为你解读2017年Java开发前景如何
社会上普遍认为程序员是一份高薪职业,确实,相较于其他行业,大多数工作1-3年的程序员年收入都在10-20万.据权威机构统计,在所有的软件开发类人才中对Java开发人才的需求量最大,达到了60%-70% ...
- 软件测试博客日记Day02-11.16日 —— 赵天宇 —— 禅道的使用和配置
禅道 1. 安装 1. 进入禅道的官方下载地址:http://www.zentao.net/download/80053.html 2. 下载禅道开源版本. 3. 正常安装,注意一定要放在根目录下. ...
- HCTF
题目:魂斗罗 介绍:这个是HCTF里面的杂项,很好玩的, 1,这个看链接可以下载(http://139.224.54.27/gogogo/hundouluo.nes),然后在网上下载一个虚拟器(htt ...
- 《java.util.concurrent 包源码阅读》27 Phaser 第一部分
Phaser是JDK7新添加的线程同步辅助类,作用同CyclicBarrier,CountDownLatch类似,但是使用起来更加灵活: 1. Parties是动态的. 2. Phaser支持树状结构 ...
- RandomAccessFile多线程下载、复制文件、超大文件读写
最近在准备面试,翻了翻自己以前写的Demo,发现自己写了不少的工具包,今天整理了一下,分享给大家. 本文包含以下Demo: 1.常用方法测试 2.在文件中间插入一段新的数据 3.多线程下载文件 4.多 ...
- 从ThoughtWorks 2017技术雷达看微软技术
ThoughtWorks在每年都会出品两期技术雷达,这是一份关于技术趋势的报告,它比起一些我们能在市面上见到的其他各种技术行情和预测报告,更加具体,更具可操作性,因为它不仅涉及到新技术大趋势,比如云平 ...
- Winform控件Tag使用规范
背景 Tag在WinForm控件中经常被用来存储临时数据,类型为object,但是当程序中多个地方使用到Tag时,容易造成Tag使用的混乱,Tag是如此重要的一个属性,应该要好好考虑下如何有效的使用T ...