ECMAScript有两种开发模式:1.函数式(过程化);2.面向对象(OOP);
一 创建对象
1.普通的创建对象
// 创建一个对象,然后给这个对象新的属性和方法; var box = new Object(); // 创建一个Object对象; box.name = 'lee'; // 创建一个name属性并赋值; box.age = 100; box.run = function(){ // 创建一个run()方法并返回值; return this.name+this.age+'运行中...'; } console.log(box.run()); // 输入属性和方法的值; // 缺点:想创建类似的对象,就会产生大量的代码;
2. 工厂模式创建对象
// 这种方法就是为了解决实例化对象产生大量代码重复的问题; function createObject(name,age){ // 集中创建函数体; var obj = new Object; // 函数体内创建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); // 实例二; console.log(box1.run()+box2.run()); // 实例保持相对独立; // 缺点:对象与实例的识别问题;无法搞清楚它们到底是那个对象的实例; console.log(typeof box1); // Object;
3.构造函数创建对象
// ECMAScript采用构造函数(构造方法)可用来创建特定的对象; function Box(name,age){ // 构造函数模式; this.name = name; // this代表对象Box; this.age = age; this.run = function(){ return this.name+this.age+"运行中..."; }; } var box1 = new Box("lee",100); // 要创建对象的实例必须用new操作符; var box2 = new Box("jack",200); // box1和box2都是Box对象的实例; console.log(box1 instanceof Box); // true;很清晰的识别box1从属于Box; // 使用构造函数,即解决了重复实例化的问题,有解决了对象识别的问题;
使用构造函数与工厂模式不同之处:
(1).构造函数方法没有显示的创建对象(new Object);
(2).直接将属性和方法赋值给this对象;
(3).没有return语句;1 // 构造函数规范:
(1).函数名(function Box)和实例化构造名(new Box)相同且大写;
(2).通过构造函数创建实例对象,必须使用new运算符;
// 构造函数和普通函数的区别: var box = new Box('lee',100); // 构造模式调用; Box('lee',200); // 普通模式调用,无效; var o = new Object(); Box.call(o,'jack',200); // 对象冒充调用; // 将Box对象作用域扩充到对象o;Box()方法的运行环境已经变成了对象o里;
构造函数的问题:
使用构造函数创建每个实例的时候,构造函数里的方法都要在每个实例上重新创建一遍;
因为ECMAScript中的函数是对象,因此每定义一个函数,也就是实例化了一个对象;
以这种方式创建函数,会导致不同的作用域链和标识符解析;
二 原型
// 我们创建的每个函数都有一个prototype(原型)属性,这个属性是一个对象;
// 用途:包含可以由特定类型的所有实例共享的属性和方法;
// 理解:prototype是通过调用构造函数创建的那个对象的原型对象;
// 使用原型的好处是可以让所有对象实例共享它所包含的属性和方法;
// 也就是说,不必在构造函数中定义对象信息(属性/方法),而是可以直接将这些信息添加到原型中;
1.原型模式(prototype添加属性和方法)
1.原型模式 function Box(){} // 声明构造函数; Box.prototype.name = 'Lee'; // 在原型里添加属性和方法; Box.prototype.age = 100; Box.prototype.run = function() { return this.name+this.age+'运行中...'; }; var box1 = new Box(); var box2 = new Box(); console.log(box1.run==box2.run); // =>true;方法引用的地址保持一致; // 在原型中多了两个属性,这两个原型属性都是创建对象时自动生成的; // 1.__proto__:构造函数指向原型对象的一个指针;它的作用:指向构造函数的原型的属性constructor; 14// IE浏览器在脚本访问__proto__会不能识别; 15 // 判断一个实例对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试; console.log(Box.prototype.isPrototypeOf(box)); // =>true; 只要实例化对象,即都会指向; // 原型模式的执行流程: // 1.先查找构造函数对象的实例里的属性或方法,若有,立刻返回; // 2.若构造函数对象的实例里没有,则去它的原型对象里找,若有,就返回; // 虽然我们可以通过对象实例访问保存在原型中的值,但却不能访问通过对象实例重写原型中的值; var box1 = new Box(); console.log(box1.name); // Lee; 原型里的值; bo1.name = 'jack'; console.log(box1.name); // Jack;实例自己赋的值; var box2 = new Box(); console.log(box2.name); // Lee;原型里的值;没有被box1修改; // 如果想要box1继续访问原型里的值,可以把构造函数里的属性删除即可; delete box1.name; // 删除实例自己的属性; console.log(box1.name); // Lee; 原型里原来的值;
2.原型与in操作符