【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:支持变量.关联数组和函数.没有对象. ...
随机推荐
- c# 条形码(求指教)
因公司需要完成一条形码打印问题,所以在找到一些资料做了一个Demo 特请教! 不知道此条形码是否正确: 图: 源码: 代码 )); } g.Save(); ...
- Kotlin(二) 函数定义
1.不带参数,不返回值的函数 fun sum(){} 2.带参数,不带返回值的函数 fun sum(a:Int){} 3.带参数,带返回值的函数 fun sum(a:Int,b:Int) : Int{ ...
- 使用 Rust 构建分布式 Key-Value Store
欢迎大家前往腾讯云社区,获取更多腾讯海量技术实践干货哦~ 引子 构建一个分布式 Key-Value Store 并不是一件容易的事情,我们需要考虑很多的问题,首先就是我们的系统到底需要提供什么样的功能 ...
- IdentityServer4(10)- 添加对外部认证的支持之QQ登录
前言 前面我们提到过IdentityServer4是可以添加外部认证的,如果外部认证支持OAuth2,那么添加到IdentityServer4是非常简单的,在ASP.NET Core下提供了非常多的外 ...
- 《Metasploit魔鬼训练营》第四章(上)
p128 wmap 和昨天一样,我用这些漏洞扫描工具去扫testfire.net或者owaspbwa都扫不出漏洞!不明白! 补充:原来是网络不知道啥时候自己断了.连上后再次扫描就成功了:
- 企业级应用TOMCAT
第1章 Tomcat 1.1 Tomcat简介 Tomcat是一个免开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不多的场合下被普遍使用,是开发调试JSP程序的首选,另 ...
- GItCandy版本库搬迁步骤
1.编译GitCandy,源码地址http://git.newlifex.com/NewLife/GitCandy 2.发布网站到文件夹 3.git网站停止运行 4.拷贝发布的网站到服务器目录&quo ...
- HTML5开发必备的工具
现在除了移动APP开发之外,比较火的就是html5开发了,现阶段的HTML5被看做是Web开发者创建流行web应用的利器,增加了对视频和Canvas2D的支持,它的优点就是可以跨平台使用,比如你是开发 ...
- 安卓自定义控件(四)实现自定义Layout
本来我是不准备写这篇文章的,我实在想不出有什么样奇怪的理由,会去继承ViewGroup然后自定义一个布局,大概是我的项目经验还不够吧,想了好久,想到了这样一个需求: 需求 如图:在项目中经常有一个这样 ...
- Web Mining and Big Data 公开课学习笔记 ---lecture0
0.1 课程主要内容:Big data technologies , Machine Learning and AI 0.6 OUTLINE: predict the future using ...