独角兽企业重金招聘Python工程师标准>>>
面向对象语言都有“类”的概念,而通过类可以创建任意多个具有相同属性和方法的对象。 JS中没有“类”的概念,它实现“对象”的方式是通过定义函数,函数里面有属性和方法。 以下开始将创建对象的几种方式。
1.工厂模式
function createPerson(name,age,job){var o=new Object();o.name=name;o.age=age;o.job=job;o.showJob=function(){console.log(this.job);}return o;}var p1=createPerson("Annie",18,"Teacher");var p2=createPerson("Bob",20,"Jser");console.log(p1);//Object {name: "Annie", age: 18, job: "Teacher", showJob: function}console.log(p2);//Object {name: "Bob", age: 20, job: "Jser", showJob: function}p2.name="Cindy";console.log(p2);//Object {name: "Cindy", age: 20, job: "Jser", showJob: function}
优:解决了JS中创建多个相似对象的问题。
缺:没有解决对象识别问题(即怎么知道一个对象的类型,JS对象类型的确定)
2.构造函数模式
function Person(name,age,job){//构造函数的函数名首字母大写this.name=name;this.age=age;this.job=job;this.showJob=function(){console.log(this.job);}}var p1=new Person("Annie",18,"Teacher");var p2= new Person("Bob",20,"JSer");console.log(p1);//Person {name: "Annie", age: 18, job: "Teacher", showJob: function}console.log(p2);//Person {name: "Bob", age: 20, job: "JSer", showJob: function}p1.showJob();//Teacher
p1和p2分别保存着Person的一个不同的实例,这两个对象都有一个constructor(构造函数)属性,指向Person。
console.log(p1.constructor==Person); //trueconsole.log(p2.constructor==Person); //true
检测对象类型:
//检测对象类型console.log(p1 instanceof Person);//trueconsole.log(p1 instanceof Object);//trueconsole.log(p2 instanceof Person);//trueconsole.log(p2 instanceof Object);//true
优:解决了对象识别问题。
缺: 此时每个方法都要在每个实例上面重新创建一次,考虑到有this对象,可通过把函数定义转移到构造函数外部来解决这个问题:
function Person(name,age,job){//构造函数的函数名首字母大写this.name=name;this.age=age;this.job=job;this.showJob=showJob;//this.showJob=function(){//console.log(this.job);//}}//可把函数定义转移到构造函数外部function showJob(){console.log(this.job);}var p1=new Person("Annie",18,"Teacher");var p2= new Person("Bob",20,"JSer");console.log(p1);//Person {name: "Annie", age: 18, job: "Teacher", showJob: function}console.log(p2);//Person {name: "Bob", age: 20, job: "JSer", showJob: function}p1.showJob();//Teacher
但是如此一来,在全局作用域中定义的函数实际上只能被某个对象调用,这让全局作用域有些名不副实。并且,如果对象需要定义很多方法,就要定义很多个全局函数,于是这个自定义的引用类型就毫无封装性可言。
3.原型模式 原型对象可让所有对象实例共享它所包含的属性和方法。
function Person(){} Person.prototype.name="Annie";Person.prototype.age=18;Person.prototype.job="Teacher";Person.prototype.showJob=function(){console.log(this.job);}var p1=new Person();console.log(p1);//Person {name: "Annie", age: 18, job: "Teacher", showJob: function}p1.showJob();//Teacher
确定对象(父对象和子对象)之间是否存在原型关系的两种判断
console.log(Person.prototype.isPrototypeOf(p1));//trueconsole.log(Object.getPrototypeOf(p1) == Person.prototype);//true
判断访问的是实例属性还是原型属性
//hasOwnPrototy()方法判断访问的是实例属性还是原型属性//只在给定属性存在于对象实例中,才会返回trueconsole.log(p1.hasOwnProperty("name"));//falsep1.name="Anna";console.log(p1.name);//Anna,来自实例console.log(p1.hasOwnProperty("name"));//truedelete p1.name;//删除实例中的name属性,恢复了对原型中name属性的连接console.log(p1.name);//Annie,来自原型console.log(p1.hasOwnProperty("name"));//false//hasOwnPrototy()结合in判断访问的是实例属性还是原型属性function hasOwnPrototyFunction(object,name){return !object.hasOwnProperty(name)&&(name in object);}console.log(hasOwnPrototyFunction(p1,"Annie"));//false
取得对象上的可枚举实例属性,object.key()
function Person(){}Person.prototype.name="Cindy";Person.prototype.age=14;Person.prototype.job="Csser";Person.prototype.showJob=function(){console.log(this.job);}var keys=Object.keys(Person.prototype);console.log(keys);//["name", "age", "job", "showJob"] var p1=new Person();p1.name="David";p1.age=21;var p1Keys=Object.keys(p1);console.log(p1Keys);//["name", "age"]
取得对象上的所有实例属性,无论是否可枚举,Object.getOwnPropertyNames()。 原生的constructor属性不可枚举。
var ownKeys=Object.getOwnPropertyNames(Person.prototype);console.log(ownKeys);//"constructor", "name", "age", "job", "showJob"]
优:保证的封装性。
缺:对于包含了引用类型值的函数来说,共享会带来一些问题:
function Person(){}Person.prototype={constructor:Person,name:"Annie",age:18,job:"Teacher",friends:["Cindy","David"],showJob:function(){console.log(this.job);}}var p1=new Person();var p2=new Person();p1.friends.push("Ella");console.log(p1.friends);//["Cindy", "David", "Ella"] console.log(p2.friends);//["Cindy", "David", "Ella"]
4.组合使用构造函数和原型模式(创建自定义类型常见的方式)。
function Person(name,age,job){this.name=name;this.age=age;this.job=job;this.friends=["Cindy","David"]}Person.prototype={constructor:Person,showJob:function(){console.log(this.job);}}var p1=new Person("Annie",18,"Teacher");var p2=new Person("Cindy",22,"Jser");p1.friends.push("Ella");console.log(p1.friends);//["Cindy", "David", "Ella"] console.log(p2.friends);//["Cindy", "David"]
5.动态原型模式
function Person(name,age,job){//属性this.name=name;this.age=age;this.job=job;//方法if(typeof this.showJob != "function"){Person.prototype.showJob=function(){console.log(this.job);};}}var p1=new Person("Annie",17,"Teacher");p1.showJob();//Teacher
6.寄生构造函数模式 寄生构造函数模式在一般情况下跟工厂模式是一模一样的,但是在如下特殊情况下:
//寄生构造函数模式function specialArray(){//创建数组var values=new Array();//添加值values.push.apply(values,arguments);//添加方法values.toPipedString=function(){return this.join("|");}//返回数组return values;}var colors=new specialArray("red","green","blue");console.log(colors.toPipedString());//red|green|blue
7.稳妥构造函数模式
function Person(name,age,job){var o=new Object;//定义私有变量和函数//....//添加方法o.showJob=function(){console.log(job);};return o;}var p1=new Person("Annie",18,"Teacher");p1.showJob();//Teacher;
除了调用showJob()外,没有别的方式可以访问其他数据成员。