面向对象是软件开发方法。面向对象的概念和应用已超越了程序设计和软件开发,扩展到如数据库系统、交互式界面、应用结构、应用平台、分布式系统、网络管理结构、CAD技术、人工智能等领域。面向对象是一种对现实世界理解和抽象的方法,是计算机编程技术发展到必定阶段后的产物。
JavaScript的面向对象主要包含了两块:1)建立对象 2)继承。接下来,咱们将走进JS对象的世界,将依次带你深刻了解函数、闭包、原型、原型链,并经过它们,最终实现建立对象和继承。数据库
若是如今有一个纯牛奶,那么咱们建立对象能够这样操做:编程
var milk ={ name:'纯牛奶', taste:'pure', price:4 }
那么若是如今有4种不一样口味的牛奶呢?也建立四个不一样的对象吗?milk一、milk二、milk三、milk4?如有一万种呢,是否也建立一万个对象?
显然,这是不合理的。这里,咱们就要引入一个概念——工厂模式。segmentfault
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来判断是否为它的一个实例——即:证实了我就是一个牛奶哦!!学习
既然有原生的构造函数,那么咱们能够不能够也本身定义构造函数呢?答案是能够的。this
通常来讲,咱们能够这样定义构造函数:人工智能
//构造函数的函数名常大写 //在这里,咱们没有显示的建立对象,没有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方法呢?
这就是构造函数的不足之处:功能相同的函数,重复声明消耗空间!看来,咱们的路尚未走到终点。
原型是函数的一个属性,是一个对象。若是函数做为构造函数使用,那么这个构造函数的全部实例,都共享这个原型对象。
「注」以前咱们回忆函数时,回忆到,函数有三个常见属性: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"]
由此咱们可见:
共享会污染数据类型,所以原型建立对象也会污染数据类型。咱们看下面一段代码:
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
在建立对象这个板块中,咱们从工厂模式开始讲起,再到构造函数,接着到原型,最后到比较完善的构造函数结合原型,在接下来的继承板块中,咱们将讲述原型链、继承以及最佳方式的相关知识,好好复习!
固然,最最最最最后,若是您喜欢这片文章,能够疯狂点赞或者收藏喔!!?