一、创建对象
创建一个对象,然后给这个对象新建属性和方法
var box = new Object(); //创建一个 Object 对象
box.name = 'Lee'; //创建一个 name 属性并赋值
box.age = 100; //创建一个 age 属性并赋值
box.run = function () { //创建一个 run()方法并返回值
return this.name + this.age + '运行中...';
};
alert(box.run()); //输出属性和方法的值
二、工厂模式
如果使用大量使用前面直接创建对象的方法,就会造成大量的重复的代码,而工厂模式可以解决多个类似对象声明和实例化对象产生大量重复的问题。
function createObject(name, age) { //集中实例化的函数
var obj = new Object();
obj.name = name;
obj.age = age;
obj.run = function () {
return this.name + this.age + '运行中...';
};
return obj;
}
var box1 = createObject('Lee', 100); //第一个实例
var box2 = createObject('Jack', 200); //第二个实例
alert(box1.run());
alert(box2.run()); //保持独立
三、构造函数
但是工厂模式存在着对象识别问题,也就是根本就无法搞清楚他们到底是哪个对象的实例,这时我们可以采用构造函数(构造方法)来创建特定的对象。
function Box(name, age) { //构造函数模式
this.name = name;
this.age = age;
this.run = function () {
return this.name + this.age + '运行中...';
};
}
var box1 = new Box('Lee', 100); //new Box()即可
var box2 = new Box('Jack', 200);
alert(box1.run());
alert(box1 instanceof Box); //很清晰的识别他从属于 Box
工厂模式与构造函数的不同
1、构造函数方法没有显示的创建对象(new Object());
2、直接将属性和方法赋值给this对象;
3、没有return语句。
构造函数的方法规范
1、函数名和实例化构造名相同且大写,(着有助于区分构造函数和普通函数);
2、通过构造函数创建对象,必须使用new运算符。
构造函数的执行过程
1、当使用了构造函数,并且new构造函数(),那么juice后台执行了new Object();
2、将构造函数的作用域给新对象,(即new Object()创建出的对象),而函数体内的this就代表newObject()出来的对象。
3、执行构造函数内的代码;
4、返回新对象(后台直接返回)。
构造函数和普通函数的区别
构造函数与普通函数的唯一区别,就是他们调用的方式不同。只不过,构造函数也是函数,必须用new运算符来调用,否则就是普通函数。
四、原型(prototype)
在学习设计模式的时候我们学习到了原型模式,而原型模式是创建型模式,用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
在JavaScript中原型是我们创建的函数的一个属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法。逻辑上的理解是,prototype通过调用构造函数而创建的那个对象原型对象。而使用原型的好处可以让所有对象实例共享它所包含的属性和方法。也就是说,不必在构造函数中定义对象信息,而是可以之间将这些信息添加到原型中。
原型模式的执行流程
1、先查找函数实例里的属性或方法,如果有,立刻返回;
2、如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回;
我们可以通过hasOwnProperty()方法检测属性是否存在实例中,也可以通过in来判断实例或原型中是否存在属性。结合这两种方法可以判断原型中是否存在属性。
原型模式下的不断演变优化
原型模式在创建对象时,它省略了构造函数传参初始化这一过程,带来的缺点就是初始化的值都是一致的。而原型最大的缺点就是它最大的优点,那就是共享。而为了解决构造传参合共享问题,可以组合构造函数+原型模式,但是这种解决放又让人觉得很怪异,方法总比问题多,于是就出现了动态原型模式。但是使用动态原型模式,就不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。所以又回到了寄生构造函数,即工厂模式和构造函数模式,它在创建一个额外方法的引用类型的时候,使用寄生构造函数比较合适。
五、继承
继承是面向对象中一个比较核心的概念。其他正统面向对象语言都会用两种方式实现继承:一个接口实现,一个继承。但是在ECMAScript中只支持继承,不支持接口实现,而实现继承的方式依靠原型链完成。在JavaScript中,被继承的函数称为超类型(父类或基类),继承的函数称为子类型(子类或派生类)。
继承的优化演变
1、组合模式
但是继承也有引用共享和超类型无法传参的问题,这时候我们可以采用借用构造函数、对象冒充(伪造对象、经典继承)的技术来解决这两种问题。但是问题又来了,借用构造函数虽然解决了刚才的两种问题,但没有原型,复用则无从谈起。所以需要原型链+借用构造函数的模式,即组合模式
2、原型继承
这种继承借助原型并基于已有的对象创建新对象,同时还不必因此创建自定义类型
3、寄生式继承
原型式+工厂模式结合而来,目的是为封装创建对象的过程。
4、寄生组合继承
组合式继承也有一点小问题,就是类型在使用过程中会被调用两次:一次是创建子类型的时候,另一次是在子类型构造函数的内部,而寄生组合继承的诞生就解决了两次调用的问题
六、总结
李老师说这一部分内容是整个JavaScript的重点,但是这些知识基本上是以前米老师都讲过,我们接触过的。虽然涉及到具体的运用还是不太明白,但是经过历练后,我相信我一定会掌握好它的。