1.私有变量和公有变量
function Obj(){ var a=0; //私有变量 var fn=function(){ //私有函数 } } //这样在函数对象Obj外部无法访问变量a和函数fn,它们就变成私有的,只能在Obj内部使用,即使是函数Obj的实例仍然无法访问这些变量和函数
function Obj(){ this.a=0; //公有变量 this.fn=function(){ //公有函数 } } //函数对象Obj在外部可以访问变量a和函数fn,实例化Obj也可以访问这些变量和函数。
2.静态变量
当定义一个函数后通过 “.”为其添加的属性和函数,通过对象本身仍然可以访问得到,但是其实例却访问不到,这样的变量和函数分别被称为静态变量和静态函数。
function Obj(){ } Obj.a=0; //静态变量 Obj.fn=function(){ //静态函数 } console.log(Obj.a); //0 console.log(typeof Obj.fn); //function var o=new Obj(); console.log(o.a); //undefined console.log(typeof o.fn); //undefined
3.使用自定义构造函数模式创建对象。这种方式有个缺陷是sayName这个方法,它的每个实例都是指向不同的函数实例,而不是同一个。
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.sayName=function() { alert(this.name); };}var person = new Person("kevin",31,"SE");person.sayName();
这个对属性来说没有什么问题,但是对于方法来说问题就很大了,因为方法都是在做完全一样的功能,但是却又两份复制,如果一个函数对象有上千和实例方法,那么它的每个实例都要保持一份上千个方法的复制,这显然是不科学的,这可肿么办呢,prototype应运而生。
4.prototype属性
无论什么时候,只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,默认情况下prototype属性会默认获得一个constructor(构造函数)属性,这个属性是一个指向prototype属性所在函数的指针。
当创建了一个foo对象之后,设置它的原型链z为3.
此时实例化对象obj,此时obj和foo的原型链都指向了prototype。为obj添加x,y属性,可以通过obj.z直接访问z属性。z属性其实不包含在实例化的obj中,但是却在obj对象的原型链上。当访问z属性的时候,在实例化中找不到对应z属性便会在它的原型链上寻找。但是通过obj.hasOwnProperty(obj.z);检测z是否是obj本身的属性。返回的是false,说明z不是obj的属性。
function foo(){}; foo.prototype.z = 3; var obj = new foo(); obj.x = 1; obj.y = 2;
根据上图可以看出Person对象会自动获得prototyp属性,而prototype也是一个对象,会自动获得一个constructor属性,该属性正是指向Person对象。
当调用构造函数创建一个实例的时候,实例内部将包含一个内部指针(很多浏览器这个指针名字为__proto__)指向构造函数的prototype,这个连接存在于实例和构造函数的prototype之间,而不是实例与构造函数之间。
function Person(name){ this.name=name; } Person.prototype.printName=function(){ alert(this.name); } var person1=new Person('Byron'); var person2=new Person('Frank');
5.使用原型模式创建对象;解决了方法3中提到的缺陷,使不同的对象的函数(如sayFriends)指向了同一个函数。但它本身也有缺陷,就是实例共享了引用类型friends,从下面的代码执行结果可以看到,两个实例的friends的值是一样的,这可能不是我们所期望的。
function Person(){}Person.prototype = { constructor : Person, name:"kevin", age:31, job:"SE", friends:["Jams","Martin"], sayFriends:function() { alert(this.friends); }};var person1 = new Person();person1.friends.push("Joe");person1.sayFriends();//Jams,Martin,Joevar person2 = new Person(); person2.sayFriends();//James,Martin,Joe
6.组合使用原型模式和构造函数创建对象,解决了方法5中提到的缺陷,而且这也是使用最广泛、认同度最高的创建对象的方法。
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; this.friends=["Jams","Martin"];}Person.prototype.sayFriends=function(){ alert(this.friends);};var person1 = new Person("kevin",31,"SE");var person2 = new Person("Tom",30,"SE");person1.friends.push("Joe");person1.sayFriends();//Jams,Martin,Joeperson2.sayFriends();//Jams,Martin
7. 动态原型模式:这个模式的好处在于看起来更像传统的面向对象编程,具有更好的封装性,因为在构造函数里完成了对原型创建。这也是一个推荐的创建对象的方法。
function Person(name,age,job){ //属性 this.name=name; this.age=age; this.job=job; this.friends=["Jams","Martin"]; //方法 if(typeof this.sayName !="function") { Person.prototype.sayName=function() { alert(this.name); }; Person.prototype.sayFriends=function() { alert(this.friends); }; }}var person = new Person("kevin",31,"SE");person.sayName();person.sayFriends();