写在前面
首先这篇文章是来自阮一峰大佬的2010年的博客!!!!戳这里
我2010的时候还在谈恋爱(逃)
自己在学习到面向对象这里有些疑惑,越学越糊涂,可能是Java的副影响。。 : -(
打算重头梳理一下,然后看了这篇博客,觉得读完了应该自己输出一遍才能是自己的。
在JavaScript里面对象是很常见,在这里函数也成为函数对象。但是这里对象又不是真正的对象,它的语法中没有Class(不涉及ES6的话),那么封装成对象应该怎么去做呢?,下面就来具体说说:
1.原始模式
我们有两只猫,它有自己的颜色和名字:
var cat1 = {
name: 'po',
color: 'orange'
}
var cat2 = {
name: 'da',
color: 'white'
}
缺点很明显,如果咱有上千只猫,那我们就要累死了。所以就需要进行改进。
2.原始模式改进
function Cat(name, color){
return {
'name': name,
'color': color
}
}
var cat1 = Cat('po', 'orange')
var cat2 = Cat('da', 'white')
这样是不是就好看了许多,但是缺点是cat1和cat2没有实质关联,两者纯粹是函数调用。这样跟我们的面向对象一点都不像。
3.构造函数模式
由于以上的缺点就出现了构造函数的形式,如下:
function Cat(name, color){
this.name = name
this.color = color
}
var cat1 = new Cat('po', 'orange')
var cat2 = new Cat('da', 'white')
alert(cat1.name) //po
alert(cat2.name) //da
这样一来就可以将cat1和cat2创造了关联,还使用了new来进行实例化。
这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。
console.log(cat1.constructor === Cat) //true
console.log(cat2.constructor === Cat) //true
上面这段话是大佬原文中的话,但是我觉得这段话造成了误导。所以重新说一下。上面两段代码为true,没错。但是!!在cat1和cat2本身上是没有constructor属性,而是会去Cat.prototype上面去找,所以准确的来说应该是这样的
console.log(Cat.prototype === Cat) //true
这里顺带提一下new做了哪些事
var temp = {}
temp.__proto__ = Cat.prototype
Cat.call(temp)
return temp
看了new做的第二件事,就应该理解了为什么cat1和cat2本身没有constructor。
构造函数模式问题
这么好的方法实现,为什么还要改进呢?
//如果我需要添加一个eat该怎么写呢?
function Cat(name, color){
this.name = name
this.color = color
this.eat = function(){ console.log('eaaaaaaaaaaaaat') }
}
var cat1 = new Cat('po', 'orange')
var cat2 = new Cat('da', 'white')
console.log(cat1.eat) //eaaaaaaaaaaaaat
console.log(cat2.eat) //eaaaaaaaaaaaaat
console.log(cat1.eat === cat2.eat) //false
看上面,确实是实现了eat的方法,但是这个方法对应的不是同一块内存,这是为什么呢?因为我们new干了这件坏事,new中每次都是创建了一个空对象。
Prototype模式
怎么改进上面的问题呢?
Cat.prototype.eat = function(){ console.log('eaaaaaaaaaaaaat') }
cat1.eat() //eaaaaaaaaaaaaat
cat2.eat() //eaaaaaaaaaaaaat
console.log(cat1.eat === cat2.eat) //true
对,直接在构造函数的原型上面去找eat方法就可以。儿子没有方法去父亲身上找,这不就有点像面向对象了吗?
未完。。。