《JS高级程序设计》第6章的读书笔记
- 创建对象(一)工场模式和构造函数模式
- 创建对象(二)原型模式和组合模式
- 创建对象(三)再探原型
- 对象继承(一)原型链
- 对象继承 (二)借用构造函数和组合继承
- 对象继承(三)原型式继承和寄生式继承
- 对象继承(四)寄生组合式继承
1 前言
JS在诞生之初,正值Java火热,其作者创造JS是模仿Java,在很多地方又做了简化,被人称为玩具语言。但是它在创造对象,继承这方面又是如此复杂。就继承而言,就有6种方式。这是在我学习的其他语言,如Python, C++, Java中,我未曾见过的。不得不说,这真的很神奇。
本文是要讲的创建对象的3种方式:工厂模式,构造函数模式,原型模式和组合模式(组合构造函数模式和原型模式)。
这些内容我是第二遍看了,但是第一遍看是在今年3月份,我刚开始学真正的JS的时候,那时候并没有看得太仔细。
当然还有其他方式,但是从《JS高程》这本书看出来,这4种方式是最重要的。
2 工厂模式
《JS高程》是这么描述工厂模式的:用函数来封装以特定接口创建对象的细节。
嗯,很理论的一句话。
简单地说,在工厂模式下,对象的创建和属性的赋值都是在一个函数中完成的。
其基本模式的代码如下:
function createPerson(name){
var o = new Object();
o.name=name;
o.sayName=function(){
return this.name;
}
return o;
}
var p1= createPerson('achao');
var p2= createPerson('yujie');
我们可以看到对象o
的创建,及其属性name
的创建都是在createPerson
中完成的。
书上说(工厂模式)“没有解决对象识别的问题”。(OS:没有问题的话,这篇博文就可以在这里结束了。
为什么呢。我们可以看到对象o
的类型Object
的使用是在函数内,当你调用createPerson
这个函数时,你是看不到里面的细节的,这就是书上说“没有解决对象识别的问题”d的原因。当然Object
可以换成任何其他类型的对象,但这不改变结论。
上述提到的问题在下一节的构造函数模式
中被解决。
3 构造函数模式
ES6之前没有class
的范畴,所以ES5是通过构造函数
创建对象。构造函数与一般的函数并没有区别,被用作创建对象,其自然被称为构造函数。
书上对此是这么说的:“不存在定义构造函数的特殊语法,只要通过new操作符来调用,那它就可以作为函数;而额任何函数,如果不通过new操作符调用,那它跟普通函数也不会有什么两样。”
构造函数模式创建对象的基本代码是这样的:
function Person(name) {
this.name = name;
this.getName = function() {
return this.name;
}
}
var p1 = Person('achao');
var p2 = Person('yujie');
与工厂模式相比,构造函数模式有以下不同:
- 没有显式地创建对象
- 直接将属性和方法赋给了this对象
- 没有return语句
以上3点关键之处在于new操作符,使用new操作符调用构造函数会经历以下4个步骤
- 创建一个新对象
- 将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
- 执行构造函数中的代码(为这个新对象添加属性)
- 返回新对象
之前提到:工厂模式没有解决对象识别的问题。
这个问题在构造函数模式中被解决:
var p1 = Person('achao');
对象的类型:Person是被暴露出来的。
console.log(p1 instanceof Person); // true
3-1 构造函数的问题
书上说:“构造函数的主要问题是:每个问题都要在每个实例上创建一遍”
this.getName = function() {
return this.name;
}
对象p1和p2各自包含一个不同的getName方法。
console.log(p1.getName == p2.getName); //false
但是,从语义上讲:这类方法不应该被共享
当然,这个问题是有解决方法的。
function Person(name) {
this.name = name;
this.getName = getName;
}
function getName() {
return this.name;
}
var p1 = new Person('achao');
var p2 = new Person('yujie');
console.log(p1.getName == p2.getName);//true
通过将函数的定义转移到构造函数外部,然后在构造函数内部引用外部函数即可。
如此,p1和p2共享了getName
函数。这注意,getName
函数中的this
指向的对象是执行时的对象,而非绑定的对象,也就是构造函数内部this绑定的被新创建的对象
。所以getName
函数能获取p1,p2各自的name
。
但是这样造成了两个问题
- 在全局作用域中定义的函数只能被某个对象调用,这名不副实。
- 全局函数没有封装性可言
问题是必须的,否则就没有下一节讲的原型模式
什么事了。
下一篇博文地址:
《JS高级程序设计》第6读书笔记:创建对象(二)原型模式和组合模式
http://blog.csdn.net/huangpin815/article/details/77428630