1. 创建对象
1.1 工厂设计模式
/** * * 工厂设计模式 * @param name * @param age * @param id * @returns {Object} */ function createObj(name,age,id) { var o = new Object(); o.name = name; o.age = age; o.id = id; o.sayInfo = function(){ return this.name+'---'+this.age+'---'+this.id; } return o; } var obj_1 = createObj('zhangsan',25,2656); console.log(obj_1.sayInfo()); //zhangsan---25---2656
1.2 构造函数设计模式
/** * 构造函数设计模式 * @param name * @param age * @param id * @constructor */ function Obj(name,age,id) { this.name = name; this.age = age; this.id = id; this.sayInof =function () { return this.name+'---'+this.age+'---'+this.id; } } var obj_1 = new Obj('zhangsan',25,2656); console.log(obj_1.sayInof()); //zhangsan---25---2656
构造函数实例一个对象的四个步骤:
1. 创建一个新的对象;
2. 将构造函数的作用域赋给新对象(因此this是指向这个新对象的);
3. 执行构造函数中的代码;
4. 返回对象
1.3 原型模式 (省去了构造函数传参初始化,也就是说,原型模式的构造函数是没有参数的空函数)
每个函数都有一个prototype(原型)属性,该属性是一个指针,指向一个对象,这个对象的用途是包含可以由特定类型的实例共享的属性和方法;
/** * 原型模式 * */ function Obj() { } Obj.prototype.name = 'zhangsnan'; Obj.prototype.age = 25; Obj.prototype.getInfo = function () { return this.name + '---' + this.age; } var obj_1 = new Obj(); var obj_2 = new Obj(); console.log(obj_1.name); console.log(obj_1.age); console.log(obj_1.getInfo()); //zhangsnan---25 console.log(obj_2.name); console.log(obj_2.age); console.log(obj_2.getInfo()); //zhangsnan---25
1.3.1 理解原型对象
只要创建一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,该属性指向原型对象,在默认的情况下,所有的原型对象都会自动获得一个constructor(构造函数)属性,这个属性是指向prototype属性所在的函数的指针。
当用构造函数创建一个新实例后,该实例的内部包含一个指针(内部属性,在ECMA第5版中管它叫[[prototype]],但没有标准访问它的方式),指向构造函数的原型对象;在Firefox,Safari,Chrome中可以通过__proto__来访问;
(1) 原型指针及constructor的指向:
(2) 对象的原型属性所指向的原型对象的判断与取得
function Obj_1() {} Obj_1.prototype.name = 'zhangsan'; function Obj_2() {} var obj_1 = new Obj_1(); //判断obj_1的原型指针指向Obj_1还是Obj_2的原型对象 console.log(Obj_1.prototype.isPrototypeOf(obj_1)); //true console.log(Obj_2.prototype.isPrototypeOf(obj_1)); //false console.log('------------------------'); //取得obj_1所指向的原型对象 console.log(Object.getPrototypeOf(obj_1)); //{name: "zhangsan", constructor: ƒ}
(3) 实例对象找属性是先找自己有没有那个属性,没有就再向原型对象里找,如果有就有,没有就没有;即使对象添加了一个和原型对象同名的属性,也不会修改原型对象的属性;
function Obj(){} Obj.prototype.name = 'zhangsan'; Obj.prototype.age = 25; var obj_1 = new Obj(); var obj_2 = new Obj(); obj_1.name = 'lisi'; console.log(obj_1.name); //'lisi' 取得obj_1自身的属性 console.log(obj_2.name); //'zhangsan' 原型对象中的name属性没有被修改 console.log(obj_1.age); //25 取得原型对象中的 console.log(obj_1.id); //undefined 自身和原型对象中都没有,则为undefined delete obj_1.name; //删除obj_1自身的name属性 console.log(obj_1.name); //'zhangsan' 取得原型中的属性(4) 判断实例中是否屏蔽了原型对象中的属性
// 判断实例中是否屏蔽了原型对象中的属性 function hasPrototypeProperty(object,pro) { return !object.hasOwnProperty(pro) && (pro in object); } function Obj(){} Obj.prototype.name = 'zhangsan'; Obj.prototype.age = 25; var obj_1 = new Obj(); var obj_2 = new Obj(); obj_1.name = 'lisi'; Object.prototype.obj_pro = '我是Objct的属性'; //判断对象是否有某个属性是自身的还是原型的,还是没有; console.log(hasPrototypeProperty(obj_1,'name')); //false console.log(hasPrototypeProperty(obj_1,'age')); //true console.log(hasPrototypeProperty(obj_1,'obj_pro')); //true 所有的对象都要继承Object的属性
(5) 获取对象上可以枚举的属性 用Object.keys() 方法
//获取对象上可以枚举的属性 用Object.keys() 方法,返回一个数组 function Obj(){} Obj.prototype.name = 'zhangsan'; Obj.prototype.age = 25; var obj_1 = new Obj(); obj_1.name = 'lisi'; console.log(Object.keys(Obj.prototype)); //["name", "age"] console.log(Object.keys(obj_1)); //["name"]
1.3.2 简单的原型语法
/** * 简单的原型语法 * */ function Obj() {} Obj.prototype = { name : 'zhangsan', age : 25 }; console.log(Obj.prototype.constructor); //ƒ Object() { [native code] } 指向Object构造函数 console.log('---------------------------'); // 改进 function Obj() {} Obj.prototype = { constructor : Obj, name : 'zhangsan', age : 25 }; console.log(Obj.prototype.constructor); //ƒ Obj() {} 指向Obj构造函数 但是可以枚举出来 for(var i in Obj.prototype){ console.log(Obj.prototype[i]); } console.log('---------------------------'); // 改进 function Obj() {} Obj.prototype = { name : 'zhangsan', age : 25 }; Object.defineProperty(Obj.prototype,'constructor',{ enumerable : false, value : Obj }); console.log(Obj.prototype.constructor); //ƒ Obj() {} 指向Obj构造函数 for(var i in Obj.prototype){ console.log(Obj.prototype[i]); }
1.3.3 原型的动态性
对原型做的任何修改都能立即从实例上反应出来,不管什么时候创建实例都如此;除非完全重写原型对象
/** *原型对象的动态性 * */ // function Obj() {} // var obj_1 = new Obj(); // Obj.prototype.name = 'zhangsan'; // Obj.prototype.age = 25; // console.log(obj_1.name); //'zhangsan' // console.log(obj_1.age); //25 //完全重写原型对象后 function Obj() {} var obj_1 = new Obj(); Obj.prototype.id = 2018; Obj.prototype = { constructor : Obj, name : 'zhangsan', age : 25 }; console.log(obj_1.name); //undefined console.log(Object.getPrototypeOf(obj_1)); //{id: 2018, constructor: ƒ} //由于完全重写原型对象时时从新建立的新对象,新开辟了一个堆内存空间来创建新的原型对象, // 而 obj_1的原型指针是指向Obj构造函数的原来的原型对象
1.4 组合使用构造函数模式和原型模式
构造函数用于定义实例属性,原型模式用于定义方法和共享属性。
//构造模式 function Obj(name,age) { this.name = name; this.age = age; } //原型模式 Obj.prototype = { constructor : Obj, getInfo :function () { return this.name+'----'+this.age } } var obj_1 = new Obj('zhangsan',25); var obj_2 = new Obj('lisi',30); console.log(obj_1.getInfo()); //zhangsan----25 console.log(obj_2.getInfo()); //lisi----30
1.5 动态原型模式
/** * *动态原型模式 */ function Obj(name,age) { this.name = name; this.age = age; console.log(Object.getPrototypeOf(this)); if(typeof this.getInfo !== 'function'){ Obj.prototype.getInfo = function () { return this.name+'---'+this.age } } console.log(typeof Obj.prototype.getInfo); } var obj_1 = new Obj('zhangsan',25); var obj_2 = new Obj('lisi',30); console.log(obj_1.getInfo()); //zhangsan---25 console.log(obj_2.getInfo()); //lisi---30
1.6 寄生构造函数模式(慎用)
思想是创建一个函数,该函数的作用仅仅是封装创建对象的代码,然后返回新创建的对象;在不能直接使用某构造函数时使用;
/** * * 寄生构造函数模式 */ function Obj_1(name,age) { this.name = name; this.age = age; } //在不能直接使用Obj_1创建实例时 function Obj(name,age) { var o = new Obj_1(name,age); o.getInfo = function () { return this.name+'----'+this.age; } return o; } var obj_1 = new Obj('zhangsan',25); console.log(obj_1); // Obj_1 {name: "zhangsan", age: 25, getInfo: ƒ} console.log(obj_1.getInfo()); // zhangsan----25
1.7 稳妥构造函数模式
不能用this,new,应用于安全执行环境
/** * *稳妥构造函数模式 */ function Obj(name,age) { var o = new Object(); o.getInfo = function () { return name+'----'+age; } return o; } var obj_1 = Obj('zhangsan',25); console.log(obj_1.name); //undefined console.log(obj_1.age); //undefined console.log(obj_1.getInfo()); //zhangsan----25