JavaScript中的原型

来源:互联网 发布:mac virtualbox u盘 编辑:程序博客网 时间:2024/05/22 00:30

JavaScript中的原型

JavaScript中得到对象的方法

第一种方法:通过new Object得到

var person = new Object();person.name = "xiaobao";person.age = 18;person.sex = "男";person.say = function(){console.log(this.name+this.age+this.sex);}person.say();

这种方法,定义多个person的时候太麻烦

第二种方法:通过json得到

var person = {"name" : "xiaobao","age" : 18,"sex" : "男","say" : function(){console.log(this.name+this.age+this.sex);}}person.say();

这种方法也是,当定义多个person的时候太麻烦

第三种方法:使用工厂模式
function createPerson(name,age,sex){var person = new Object();person.name = name;person.age = age;person.sex = sex;person.say = function(){console.log(this.name+this.age+this.sex);}return person;}var person1 = createPerson("xiaobao",18,"男");person1.say();

这种方法可以通过传递参数的方式可以定义多个person,但是对于得到的对象却不知道是什么类型

第四种方法:使用构造函数
function Person(name,age,sex){this.name = name;this.age = age;this.sex = sex;this.say = function(){console.log(this.name+this.age+this.sex);}}var person1 = new Person("xiaobao",18,"男");person1.say();console.log(person1 instanceof Person);

这种方法实际上跟工厂模式一样,不同之处只是先定义一个Person所谓的类,再用new的方法来创建一个一个的对象,但是say方法在每个对象创建后都存在了个方法拷贝( 但是我们发现代码在只有调用时,say方法才会在堆中创建),这样就增加了内存的消耗了,如果在对象中有大量的方法时,内存的消耗会高,这样不行了。简单地说就是因为say方法是一个闭包函数,每次创建一个对象,say方法就会多一个,占用的内存会越来越多。

function Person(name,age,sex){this.name = name;this.age = age;this.sex = sex;this.say = say;}function say(){console.log(this.name+this.age+this.sex);}var person1 = new Person("xiaobao",18,"男");person1.say();console.log(person1 instanceof Person);
这种方法是将say方法拿出来作为全局函数,但是这样导致window也可以进行调用,失去了封装的意义,而且后面代码越写越多之后,方法越来越多,后期开发起来和优化起来都特别麻烦。
因为以上方法都不理想,所以用原型的方法来创建对象

function Person(){}Person.prototype.name = "xiaobao";Person.prototype.age = 18;Person.prototype.sex = "男";Person.prototype.say = function(){console.log(this.name+this.age+this.sex);}var person1 = new Person();person1.say();console.log(person1 instanceof Person);//用来检测person1是不是指向Person的原型对象console.log(Person.prototype.isPrototypeOf(person1));
先定义一个对象(首字母大写),再使用原形来给对象赋值,这样就将对象的属性和值放在了对象原型中,而且say方法只有对象自身可以访问,外界无法访问。
原型是js中非常特殊一个对象,当一个函数创建之后,会随之就产生一个原型对象,当通过这个函数的构造函数创建了一个具体的对象之后,在这个具体的对象中就会有一个属性指向原型。

//用来检测person1是不是指向Person的原型对象console.log(Person.prototype.isPrototypeOf(person1));//检测person1的构造器是不是指向Person对象console.log(p1.constructor == Person);//检测属性是不是在自己的内存中console.log(p1.hasOwnProperty("name"));//可以用delete语句来删除我们赋予对象自己的属性,但是原型中的是无法删除的delete p1.name;//检测某个对象自己或者对应的原型中是否存在某个属性console.log("name" in p1);//检测属性不在自己,在原型中function hasPrototypeProperty(obj,prop) {if (!obj.hasOwnProperty(prop)) {if (prop in obj) {return true;}}return false;}console.log(hasPrototypeProperty(p1,"name"));
原型重写
如果对象中存在大量的属性或者方法的时候,使用之前的方式,感觉要写大量的【对象.prototype.属性名 】,感觉不是很好,那么json的方式来写:
function Person() {}Person.prototype = {name : "xiaobao",age : 18,say : function() {alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");}}var p1 = new Person();p1.say()var p2 = new Person();p2.name = "张三";p2.age = 20;p2.say();
但是这种写法,是将该对象的原型覆盖(这两种写法不一样的, 第一种是扩充,第二种是覆盖) 
function Person() {}Person.prototype = {constructor:Person,//手动指向Personname : "刘帅哥",age : 18,say : function() {alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");}}var p1 = new Person();p1.say()var p2 = new Person();p2.name = "张三";p2.age = 20;p2.say();//此时p1的构造器不在指向Person,而是指向了Object//因为我们覆盖了Person的原型,所以如果constructor比较重要的话,</span><span style="color:#f8f8f2;font-weight: normal; font-family: Consolas; font-size: 10pt;">//我们可以收到指向console.log(p1.constructor == Person);
封装--原型创建对象
因为原型存在,我们实现了对象的封装,但是这种封装也同样可能存在问题的。
1、 我们无法像使用构造函数的那样将属性传递用于设置值
2、 当属性中有引用类型, 可能存在变量值的重复

function Person() {}Person.prototype = {constructor:Person,name : "刘帅哥",age : 18,friends:["老孙","老牟"],say : function() {alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");}};var p1 = new Person();p1.friends.push("老刘");alert(p1.friends);//因为p1和p2对象指向了同一个原型链,所以当p1的friends发生变化是p2页就跟着var p2 = new Person();alert(p2.friends);
为了解决原型所带来的问题,需要通过组合构造函数和原型来实现对象的创建将:属性在构造函数中定义,将方法在原型中定义。这种有效集合了两者的优点,是目前最为常用的一种方式。
//属性在构造方法定义function Person(name,age,friends) {this.name = name;this.age = age;this.friends = friends;}/*** 此时所有的属性都是保存在自己的内存中* 方法都是定义在prototype(原型)中*///方法在原型中定义Person.prototype = {constructor:Person,say : function() {alert("我的名字是: "+this.name+",我今年"+this.age+"岁了");}};var p1 = new Person("刘帅哥",18,["老孙","老徐"]);p1.friends.push("老刘");alert(p1.friends);var p2 = new Person("曾小贤",20,["小丽","小美"]);alert(p2.friends);
最终的定义 javascript 对象的方案就是基于组合的方式定义,将属性的定义放在构造函数中,将方法的定义放在原型中。

2 0