面向对象是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到一定阶段后的产物。
JavaScript的面向对象主要包含了两块:1)创建对象 2)继承。接下来,我们将走进JS对象的世界,将依次带你深入了解函数、闭包、原型、原型链,并通过它们,最终实现创建对象和继承。

创建对象

如果现在有一个纯牛奶,那么我们创建对象可以这样操作:

var milk ={name:'纯牛奶',taste:'pure',price:4
}

那么如果现在有4种不同口味的牛奶呢?也创建四个不同的对象吗?milk1、milk2、milk3、milk4?若有一万种呢,是否也创建一万个对象?
显然,这是不合理的。这里,我们就要引入一个概念——工厂模式。

工厂模式

function createMilk(name,taste,price){return {name:name,taste:taste,price:price}
}var milk1 = createMilk('纯牛奶','pure',4);
var milk2 = createMilk('有机奶','organic',4);
var milk3 = createMilk('低脂奶','low-fat',4);

在这里,我们实用一个函数,传入产品名、口味、价格3个参数,返回一个对象。这样,我们只要调用这个函数,并传入不同的参数,即可构建不同的对象。这就是工厂模式。

工厂模式有优点也有缺点:
1)优点:简单易懂、常见且实用。
2)缺点:对于如何证明我是一个牛奶这个问题上,则无法证明。//这句如若无法理解的话,可以暂时忽略,继续往下看哦!

函数

为了更好的讲解构造函数、原型、原型链等,建议你复习一下函数的一些基础知识,如果你已经对函数有深入的了解,可以选择跳过。戳这里:JS函数的一些基础知识

构造函数

还记得我们之前在讲述工厂模式的缺点时,所说的那句“对于如何证明我是一个牛奶这个问题上,则无法证明。”吗?接下来,就是见证奇迹的时刻!

原生构造函数
var obj = new Object();
var add = new Function('a','b','return a+b');console.log(obj instanceof Object);//true
console.log(add instanceof Function);//true

Object和Function都是原生的构造函数,在这里我们就可以使用instanceof来判断是否为它的一个实例——即:证明了我就是一个牛奶哦!!

既然有原生的构造函数,那么我们可以不可以也自己定义构造函数呢?答案是可以的。

构造函数

一般来说,我们可以这样定义构造函数:

//构造函数的函数名常大写
//在这里,我们没有显示的创建对象,没有return语句,却将属性和方法赋值给了this。
function Milk(name,taste,price){this.name = name;this.taste = taste;this.price = price;
}
//new操作符会默认的创建一个新对象,将function的this指向对象,然后将该对象赋值,对象就有了三个属性。
var milk1 = new Milk('纯牛奶','pure',4);
console.log(milk1 instanceof Milk);//true
构造函数的不足
function Milk(name,taste,price){this.name = name;this.taste = taste;this.price = price;this.say = function(){console.log('Hello World');};
}
var milk1 = new Milk('纯牛奶','pure',4);
var milk2 = new Milk('纯牛奶','pure',4);

假设我们创建了一个Milk的构造函数,里面除了属性还带有一个say的方法,当我们new了两个对象之后,两个对象milk1和milk2是否都包含了功能相同的say方法呢?
这就是构造函数的不足之处:功能相同的函数,重复声明消耗空间!看来,我们的路还没有走到终点。

原型prototype

什么是原型?

原型是函数的一个属性,是一个对象。如果函数作为构造函数使用,那么这个构造函数的所有实例,都共享这个原型对象。
「注」之前我们回忆函数时,回忆到,函数有三个常见属性:name,length和prototype喔!如果遗忘,可以戳这里:JS函数的一些基础知识!

原型详解

1)constructor
原型的constructor是一个对象,我们可以这样简单的验证一下:

Object.prototype.constructor === Object //true

2)读写

function Milk() {}Milk.prototype.name = '纯牛奶';
Milk.prototype.taste = 'pure';
Milk.prototype.price = 4;
Milk.prototype.say = function(){console.log('Hello World');
};
var milk1 = new Milk();

运行的结果如下:

通过这种方式,可以解决内存问题。但也会因此而共享name,taste,price和say(),尤其是共享name,taste和price,会产生问题。

3)isPrototypeOf
我们可以通过isPrototypeOf来进行原型的判定,如下:

function Milk() {}Milk.prototype.name = '纯牛奶';
Milk.prototype.taste = 'pure';
Milk.prototype.price = 4;
Milk.prototype.say = function(){console.log('Hello World');
};
var milk1 = new Milk();
console.log(Milk.prototype.isPrototypeOf(milk1));//true
原型、构造函数和实例之间的关系

原型是函数的一个属性,是一个对象。如果函数作为构造函数使用,那么这个构造函数的所有实例,都共享这个原型对象。

原型的不足

原型的不足,本质上是共享的缺陷。我们可以看如下一段代码:

var price = 10;
var priceCopy = price;
priceCopy = 20;
console.log(price,priceCopy);//10,20

我们再看如下一段代码:

var taste = ['pure','organic'];
var tasteCopy = taste;
tasteCopy.push('low fat');
console.log(taste,tasteCopy);//["pure", "organic", "low fat"],["pure", "organic", "low fat"]

由此我们可见:

  • 对于基本类型,price和priceCopy是在内存中分别挖两块地方存储,因此,priceCopy的值改变的时候,并不影响price的值;
  • 而对于引用类型,name和nameCopy是调用同一个引用,引用同一个数据,当我们在nameCopy添加一个名称的时候,引用的数据就添加了一个值,name也就因此而受到了影响,这就是数据的污染。

共享会污染数据类型,因此原型创建对象也会污染数据类型。我们看下面一段代码:

function Milk(){}
Milk.prototype.taste = ['pure','organic'];var m1 = new Milk();
var m2 = new Milk();m2.taste.push('low fat');console.log('m1',m1.taste);//["pure", "organic", "low fat"]
console.log('m2',m2.taste);//["pure", "organic", "low fat"]

通过这段代码,我们可以清楚的了解到原型创建对象主要的不足具体表现在:

  • 原型创建对象会产生共享的问题
  • 不能再额外传递参数进去。

构造函数结合原型

构造函数有一定的优缺点,原型也有一定的优缺点,如果我们把两者优点结合,将会是一种不错的创建对象的方式。我们看如下的代码:

function Milk(name,taste,price){//构造函数独享属性this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}
var m1 = new Milk('纯牛奶','pure','4');
m1.say();//纯牛奶

在这段代码中,我们使用构造函数来独享属性,以避免原型创建对象会产生的共享问题,当然,我们也使用原型共享方法,从而达到拒绝功能相同的函数导致的重复声明消耗空间问题。

构造函数结合原型的一些细节问题

在学习来构造函数结合原型创建对象的基础之上,我们来关心一些细节性的问题,以便于我们深入了解构造函数结合原型。如,构造函数和原型上的属性是否会覆盖,优先顺序又是什么?再如,如何判断属性是在原型上还是在构造函数之上呢?
1)属性的覆盖
我们通过如下两段代码,总结关于构造函数结合原型的属性覆盖:

//1
function Milk(name,taste,price){//构造函数独享属性this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log(m1.name);//纯牛奶
//2
function Milk(name,taste,price){//构造函数独享属性//this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log(m1.name);//牛奶

从两端代码中,我们对比得知,实例上的属性会覆盖原型上的属性。即:会先在实例中查找,如没有,则再在原型上查找。
2)属性的判断
(1)in操作符
我们可以通过如下三段代码,总结关于in操作符的知识,即:只要对象里有值,即无论是在构造函数之上还是在原型之上均返回true,若都不在,则返回false。

//1
function Milk(name,taste,price){//构造函数独享属性this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log('name' in m1);//ture
//2
function Milk(name,taste,price){//构造函数独享属性//this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log('name' in m1);//ture
//3
function Milk(name,taste,price){//构造函数独享属性//this.name = name;this.taste = taste;this.price = price;
}
//Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log('name' in m1);//false

(2)hasOwnProperty
我们可以通过如下两段代码,总结关于in操作符的知识,即:判断是在实例上还是原型上,挂在实例上返回true,反之false。

//1
function Milk(name,taste,price){//构造函数独享属性this.name = name;this.taste = taste;this.price = price;
}
//Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log(m1.hasOwnProperty('name'));//true
//2
function Milk(name,taste,price){//构造函数独享属性//this.name = name;this.taste = taste;this.price = price;
}
Milk.prototype.name = '牛奶';
Milk.prototype.say = function(){//原型共享方法console.log(this.name);
}var m1 = new Milk('纯牛奶','pure','4');
console.log(m1.hasOwnProperty('name'));//false

小结

创建对象这个板块中,我们从工厂模式开始讲起,再到构造函数,接着到原型,最后到比较完善的构造函数结合原型,在接下来的继承板块中,我们将讲述原型链、继承以及最佳方式的相关知识,好好复习!

继承(更新中)

当然,最最最最最后,如果您喜欢这片文章,可以疯狂点赞或者收藏喔!!?

深入理解JS的面向对象(更新中)相关推荐

  1. mysql查询更新优化_mysql查询优化(持续更新中)

    1.索引不会包含有NULL值的列 (1)   应尽量避免在where子句中对字段进行null值判断,否则将导致引擎放弃使用索引而进行全表扫描 (2)   数据库设计时不要让字段的默认值为null,可以 ...

  2. 理解js中的面向对象

    目录 前言: 一点疑问: 1.封装 2.继承 原型链的查找机制 不容易理解的点: ----重点在最后---- 前言: js是一门面向对象的语言,但是又没有类的概念,虽然后来加入了class,但也就是个 ...

  3. 彻底理解js中this

    相关博文:http://blog.csdn.net/libin_1/article/details/49996815 彻底理解js中this的指向,不必硬背. 首先必须要说的是,this的指向在函数定 ...

  4. 理解JS中的this的指向

    原文地址:https://www.cnblogs.com/pssp/p/5216085.html#1 首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到 ...

  5. 前端知识点总结——JS高级(持续更新中)

    前端知识点总结--JS高级(持续更新中) 1.字符串 什么是: 连续存储多个字符的字符数组 相同: 1. 下标 2. .length 3. 遍历 4. 选取: slice(starti[, endi] ...

  6. 【Spring Boot官方文档原文理解翻译-持续更新中】

    [Spring Boot官方文档原文理解翻译-持续更新中] 文章目录 [Spring Boot官方文档原文理解翻译-持续更新中] Chapter 4. Getting Started 4.1. Int ...

  7. python基础笔记,超详细,包含面向对象基础,爬虫实战【持续更新中...】

    前言: 本笔记中的函数和方法同义,面向python3 本笔记部分概念及代码由newbing搜集整理得出 本笔记适合有一定其他编程语言基础的同学,因为笔记中省略了部分基础概念(比如整型,浮点型等基本数据 ...

  8. 彻底理解js中this的指向

    首先必须要说的是,this的指向在函数定义的时候是确定不了的,只有函数执行的时候才能确定this到底指向谁,实际上this的最终指向的是那个调用它的对象(这句话有些问题,后面会解释为什么会有问题,虽然 ...

  9. 简单粗暴地理解js原型链–js面向对象编程

    简单粗暴地理解js原型链–js面向对象编程 作者:茄果 链接:http://www.cnblogs.com/qieguo/archive/2016/05/03/5451626.html 原型链理解起来 ...

最新文章

  1. 《棋牌游戏服务器》玩法服务器架构
  2. ubuntu android2.3 emulator,Android Studio 2.3 Ubuntu 16.10 emulator do not start
  3. autojs怎么post协议_autojs QQ群post签到(五)
  4. C++中int *p[4]和 int (*q)[4]的区别
  5. linux查看r的安装路径,在Linux CentOS 6.5版上安装R3.1.1的问题(检查LDFLAGS以获取Fortran库的路径)...
  6. Spring beans配置方案(一) 学习笔记
  7. 欢迎使用CSDN-markdown编辑器【转载】
  8. server2008R2WSUS管理之 计算机管理
  9. Codeforces Round #253 DIV1 C 馋
  10. matlab 读取同一文件中所有图像_matlab 批量读取文件夹内所有图片的几种方法
  11. 相机sd卡格式化后还能不能数据再恢复
  12. 计算机考研数学一大纲2016,2016考研大纲:计算机专业
  13. Cent OS7基础 第五节
  14. Excel怎么设置密码保护工作表
  15. 文字底部或者中间 加横线
  16. 绩效评估:最佳做法和要问的首要问题
  17. 国内外计算机科学与技术发展前景,计算机科学与技术的现状及发展趋势
  18. LAPACK的C/C++接口及代码实例
  19. adobe acrobat pro dc 无法打开PDF_PDF编辑Acrobat Pro软件教程 Acrobat XI Pro 全面技能标准培训视频...
  20. python获取视频缩略图_python接收图片变成缩略图

热门文章

  1. nginx 反向代理 apache 服务
  2. iOS开发网络数据之AFNetworking使用
  3. golang for android
  4. Windows应用程序文件格式转换控件LEADTOOLS ePrint Professional
  5. angular学习笔记(四)- input元素的ng-model属性
  6. Ruby 3 有望引入静态类型
  7. DNS基本原理与配置
  8. Struts2 interceptor使用经验小结
  9. Raid信息丢失数据恢复及oracle数据库恢复验证方案
  10. 关于数据库中存储过程 的用户从属。。