一,创建对象 var box = new Object(); box.name = 'lee'; box.age = 23; box.run = function () { return this.name + this.age + " run...."; } alert(box.run()); 上面创建了一个对象,并且创建属性和方法,在run()方法里的this,就是代表box 对象本身。这种是JavaScript 创建对象最基本的方法,但有个缺点,想创建一个类似的对象,就会产生大量的代码。 var box1 = new Object(); box1.name = 'jack'; box1.age = 24; box1.run = function () { return this.name + this.age + " run...."; } alert(box1.run()); 为了解决多个类似对象声明的问题,我们可以使用一种叫做工厂模式的方法,这种方法就是为了解决实例化对象产生大量重复的问题。 1.工厂模式 function createObject(name, age) { var obj = new Object(); //创建对象 obj.name = name; //添加属性 obj.age = age; obj.run = function () { //添加方法 return this.name + this.age + " runing..."; }; return obj; //返回对象 }; var box2 = createObject('hg', 100); //创建第一个对象 var box3 = createObject('wj', 200); //创建第二个对象 alert(box2.run()); //打印run方法 alert(box3.run()); 工厂模式:就解决了实例化对象,产生大量重复的问题.但是又引出了一个新的问题,声明出来的对象都是object的类型,无法区分它们. 2.构造函数方法的方式创建对象 function Box(name, age) //创建对象 { this.name = name; //添加属性 this.age = age; this.run = function () { return this.name + this.age + " runing..."; }; }; var box1 = new Box('lee', 100); //实力化 var box2 = new Box('wenjing', 200); alert(box1.run()); alert(box2.run()); alert(box1 instanceof Box); //true 构造函数方式:(改良后的工厂方法) (1)构造函数没有使用new object,但是系统会自动调用var obj=new object(). (2)this 相当于 obj. (3)构造函数方式没有像工厂一样return obj; 后台自动返回对象. 构造函数的方法有一些规范: (1)函数名和实例化构造名相同且大写.(非强制,但是有助于区分与普通函数之间的区别). (2)通过构造函数创建对象,一定要用new (3)解决了对象识别问题box1 instanceof Box 返回ture 注意: A;this的使用 this如果在全局,就是代表windows对象,在构造函数内,代表构造函数所声明的对象.构造函数用普通函数调用,一般是无效的,必须使用new运算符. B:对象冒充调用: var o = new Object(); Box.call(o, 'Jack', 200) //对象冒充调用 alert(o.run()); //正确 C:探讨一下构造函数体内构造方法 function Box(name, age) //创建对象 { this.name = name; //添加属性 this.age = age; this.run = function () { return this.name + this.age + " runing..."; }; }; var box1 = new Box('hg', 123); var box2 = new Box('wj', 321); alert(box1.run == box2.run); //false 两个对象使用的run函数不相同.解决引用地址不同,可以通过对象外面引用同一个函数,来解决. function Box(name, age) //创建对象 { this.name = name; //添加属性,实例属性 this.age = age; this.run = run; //实例方法 }; function run() { return this.name + this.age + " runing..."; } var box1 = new Box(); var box2 = new Box(); alert(box1.run()); alert(box1.run == box2.run); //true 用全局的run来解决唯一性,但是又带来了新的问题.run暴露在外边.对象调用this代表box,被当作普通函数的时候,this代表window. 3.原型 每一个函数都有一个prototype(原型)属性,这个属性是一个对象,它的用途是包含特定类型的所有实例共享的属性和方法. function Box() {}; //原型 Box.prototype.name = 'hg'; //原型属性 Box.prototype.age = 23; Box.prototype.run = function () //原型方法 { return this.name + this.age + " runing..."; } var box1 = new Box(); var box2 = new Box(); alert(box1.run()); alert(box1.run == box2.run); //true 如果是实例方法,不同的实例化,他们的方法地址是不同的地址. 而原型方法,他们的地址是共享的,大家都是一样的. 构造函数方式 原型模式方式 __proto__ 是一个指针,指向prototype的原型对象. 在声明原型的时候,多了2个属性,这2个属性都是创建对象自动生成的, __proto__属性是实例指向原型对象的一个指针.他的作用就是指向构造函数的原型属性constructor. PS:IE 浏览器在脚本访问__proto__会不能识别,火狐和谷歌浏览器及其他某些浏览器均能识别。虽然可以输出,但无法获取内部信息。 alert(box1.__proto__); //[object Object] alert(box1.constructor); //可以获取构造函数本身. 判断一个对象是否指向了该构造函数的原型对象,可以使用isPrototypeOf()方法来测试。 alert(Box.prototype.isPrototypeOf(box1)); //true 原型的执行过程: 1.先查找构造函数实例里的属性或方法,如果有,立刻返回; 2.如果构造函数实例里没有,则去它的原型对象里找,如果有,就返回; 这说明原型是原型,对象是对象.通过原型创建的对象依旧可以添加自己的属性和方法,但是这个属性和方法不影响原型.说明我们可以通过对象访问原型的值,但是不可以改写原型的值. Box.prototype.name = 'hg'; //原型属性 Box.prototype.age = 23; Box.prototype.run = function () //原型方法 { return this.name + this.age + " runing..."; } var box1 = new Box(); var box2 = new Box(); alert(box2.name); //hg box2.name = 'wj'; //重写name的属性 alert(box2.name); //wj delete box2.name; //删除box2的对象name属性 alert(box2.name); //hg //可以通过prototype来重写原型中的属性. Box.prototype.name = 'kkk'; //可以重写原型的属性 可以使用hasOwnProperty()函数来验证:构造函数的实例里是否有属性. alert(box.hasOwnProperty('name')); //实例里有返回true,否则返回false in操作符判断属性是否在对象中,无论属性存在于实例或者原型中都返回true. alert('name' in box1); //true alert('name' in box2); //true 判断是否属性只存在于原型,而实例中没有. function isProperty(object, property) { //判断原型中是否存在属性 return (!object.hasOwnProperty(property)) && (property in object); } var box = new Box(); alert(isProperty(box, 'name')) //true,如果原型有 注意: var box = new Box(); alert(box.prototype); //错 alert(box.__proto__); //可以,但是IE本身是无法反问的. alert(Box.prototype); //可以 如果想访问prototype,用Box.prototype可以. 使用字面量的方式创建原型对象. function Box() {} Box.prototype = { name:'hg', age:23, run:function () { return this.age + this.name + " runing..."; } }; var box = new Box(); alert(box.run()); //正常打印 注意:Box.prototype = {};创建了一个新的对象,不再指向Box了. 可以用constructor:Box进行强制转换. function Box() {} Box.prototype = { name:'hg', age:23, run:function () { return this.age + this.name + " runing..."; } }; //这里就切断了之前的原型与对象的链接.不会保存以前的原型中的属性 Box.prototype = { age:100, }; var box = new Box(); alert(box.run()); //run is undefined 原型的缺点:第一:省略了传参的过程,所有的实例,初始化都是一样的.无法保持独立性.第二个缺点也是它最大的优点就是,所以的都是共享的. //原型的缺点 function Box() {} Box.prototype = { constructor:Box, name:'hg', age:100, family:['gege', 'jiejie', 'didi'], run:function () { return this.name + this.family; } }; var box1 = new Box(); alert(box1.family); box1.family.push('meimei'); //更改了原型 alert(box1.family); var box2 = new Box(); alert(box2.family); //受box1的操作影响 //组合构造函数+原型模式 function Box(name, age) { this.name = name; this.age = age; this.family = ['gg','jj','mm']; }; Box.prototype = { constructor:Box, run:function () { return this.name + ' ' + this.family; }, }; var box = new Box(); alert(box.family); box.family.push('dd'); //添加新的数据 alert(box.family); var box1 = new Box(); alert(box1.family); //没有改变 这样family并没有被共享. //动态原型模式 //将原型封装到构造函数里面 function Box(name, age) { this.name = name; this.age = age; this.family = ['gg','jj','mm']; //原型初始化开始 Box.prototype.run = function () { return this.name + ' ' + this.family; }; //原型初始化结束 }; 事实上原型只初始化一次就可以了,所以想办法第一次初始化调用一次就好了. function Box(name, age) { this.name = name; this.age = age; this.family = ['gg','jj','mm']; //这样就只初始化一次,判断run函数是否存在. if (typeof this.run != 'function'){ Box.prototype.run = function () { return this.name + ' ' + this.family; }; } }; Var box = new Box(‘hg’, 123); Alert(box.run()); 使用动态原型模式,要注意一点,不可以再使用字面量的方式重写原型,因为会切断实例和新原型之间的联系。重写原型prototype就将之前的原型给替换了. //寄生构造模式 = 工厂模式 + 构造函数 function Box(name, age) { var obj = new Object(); obj.name = name; obj.age = age; obj.run = function () { return this.name + this.age + '运行中...'; }; return obj; } var box = new Box('hg', 123); alert(box.run()); //稳妥构造函数 不允许使用this和new 在一些安全的环境中,比如禁止使用this 和new,这里的this 是构造函数里不使用this,这里的new 是在外部实例化构造函数时不使用new。这种创建方式叫做稳妥构造函数。 function Box(name , age) { var obj = new Object(); obj.run = function () { return name + age + '运行中...'; //直接打印参数即可 }; return obj; } var box = Box('Lee', 100); //直接调用函数 alert(box.run()); 稳妥构造函数和寄生构造函数很类似.