【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:支持变量.关联数组和函数.没有对象. ...
随机推荐
- windows服务器下iis的性能优化 服务器
IIS性能优化 1.调整IIS高速缓存 HKEY_LOCAL_MACHINE SystemCurrentControlSetServicesInetInfoParametersMemoryCacheS ...
- jenkins+docker 持续构建非docker in docker jenkins docker svn maven
工欲善其事必先利其器,为了解脱程序员的,我们程序员本身发明了很多好用的工具,通过各种工具的组合来达到我们想要的结果 本文采用jenkins docker svn maven作为相关工具,项目sprin ...
- linux kernel态下使用NEON对算法进行加速
ARM处理器从cortex系列开始集成NEON处理单元,该单元可以简单理解为协处理器,专门为矩阵运算等算法设计,特别适用于图像.视频.音频处理等场景,应用也很广泛. 本文先对NEON处理单元进行简要介 ...
- 《Linux命令行与shell脚本编程大全》第九章 安装软件程序
包管理系统(PMS):用来进行软件安装.管理和删除的命令行工具 9.1包管理基础 1.主流的Linux发行版都采用了某种形式的包管理系统来控制软件和库的安装 2.PMS用一个数据库来记录:系统上安装了 ...
- 掌握numpy(四)
数组的累加(拼接) 在前面讲了使用切片方法能够对数组进行切分,使用copy对切片的数组进行复制,那么数组该如何拼接呢? a1 = np.full((2,3),1)#填充数组 a2 = np.full( ...
- MySQL执行一个查询的过程
总体流程 客户端发送一条查询给服务器: 服务器先会检查查询缓存,如果命中了缓存,则立即返回存储在缓存中的结果.否则进入下一阶段: 服务器端进行SQL解析.预处理,再由优化器生成对应的执行计划: MyS ...
- 关于HTML5新手应该知道的几点知识
随着移动互联网的快速发展,HTML5迅速崛起,我们的生活的方方面面都被HTML5渗透着.HTML5在PC端.移动端上均应用广泛,被称为Web的未来.而随着Google正式停止支持Swiffy,HTML ...
- 关于laravel 用paginate()取值取不到的问题
前几天在写api的时候,出现了一个比较奇怪的问题,用paginate()方法取值取不到的问题,我奇怪的是,我用paginate()方法取值是直接复制粘贴之前自己写过的api中的代码的,怎么突然取不到了 ...
- Android - "cause failed to find target android-14" 问题
在导入别人的工程项目时经常会遇到各种问题,本文中的就是其中SDK不对导致的 在导入项目时已经修改了 两个build.gradle文件 错误的原因是后面中这两项没修改. compileSdkVers ...
- 腾讯 AI Lab 计算机视觉中心人脸 & OCR团队近期成果介绍(3)
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 作者:周景超 在上一期中介绍了我们团队部分已公开的国际领先的研究成果,近期我们有些新的成果和大家进一步分享. 1 人脸进展 人脸是最重要的视觉 ...