- 面向对象的数据属性包括configurable(能否重新配置/删除), enumerable(能否枚举), writable(能否修改), value(属性的数据值)。\
1 var obj={ 2 name:"Jonathan" 3 }; 4 console.log(obj.name);
- 对象Obj的name属性的值(value)为Jonathan.
- 可以通过defineProperty来修改configurable, enumerable和writable三个属性。在修改前,这三个属性均为true。
1 var obj={ 2 name:"Jonathan" 3 }; 4 console.log(obj.name);//Jonathan 5 Object.defineProperty(obj,"name",{ 6 writable:false 7 }) 8 obj.name="Else"; 9 console.log(obj.name);//Jonathan
3. 需要注意的是,一旦对象的configurable被改成false之后,就不能再改回true了,若改成了true,则会报错。比如:
1 var person={ 2 weight:120 3 } 4 Object.defineProperty(person,"weight",{ 5 configurable:false 6 }) 7 Object.defineProperty(person,"weight",{ 8 configurable:true, 9 value:100, 10 })//TypeError: Cannot redefine property: weight
- 访问器属性除了数据值value不包括,还包括一对setter和getter函数。setter函数可以通过设置一个属性的值,来修改其他属性的值。比如:
这里要注意的是,当用户修改book的属性year时,会调用getter和setter函数,修改_year和edition的值。这个方法可以有效防止私有变量_year被修改。
1 var book={ 2 _year:2004, 3 edition:1 4 } 5 Object.defineProperty(book,"year",{ 6 get:function(){ 7 return this._year; 8 }, 9 set:function(val){//这里val是year的形参,当修改该值的时候,会调用setter getter 函数 10 if(val>2004){ 11 this._year=val; 12 this.edition+=val-2004; 13 } 14 } 15 }); 16 book.year=2005;//when revise the value of year, this action calls the setter and getter function, which then revise the private variable _year 17 console.log(book.edition);//2
通过defineProperties(这里要注意后缀)可以定义多个属性,比如book初始化为 var book={}的时候,通过defineProperty定义它的属性。例如:
var paper={}; Object.defineProperties(paper,{ _year:{ value:2003, }, _author:{ name:"Jonathan", } }) console.log(paper._year);//2003
- 创建对象
- 工厂模式:通过函数接口来批量创建对象,例如
1 function createObj(age, name, weight, grade){ 2 var obj=new Object(); 3 obj.age=age; 4 obj.name=name; 5 obj.weight=weight; 6 obj.grade=grade; 7 8 return obj;//这里有return 语句!! 9 } 10 var p1=createObj(10,"Jonathan", 120, "Year 2"); 11 console.log(p1.grade); 12 console.log(typeof p1);//object 13 14 var a=new String("a"); 15 console.log(typeof a);//object, you cannot tell the type difference between p1 and a.
但是你无法知道这个对象的类型,比如上例中的a 和 p1。
- 所以有一种新的构造函数模式来构造对象。
1 function Person(age, name, weight){ 2 this.age=age; 3 this.name=name; 4 this.weight=weight; 5 } 6 var p2=new Person(10,"Tom",70); 7 console.log(p2.age);//age
这里没有显示的创建对象,只是通过this关键词将属性赋值给了对象属性,并且没有return语句。
如果想知道p2的构造函数,通过p2.constructor即可得知。
-
- 构造函数作为一种特殊的函数体,它的调用方法区别于其它的函数。任何函数通过new操作符来调用,那么该函数就可以作为构造函数。
- 比较下面三种调用方法:
1 var p2=new Person(10,"Tom",70);//当作构造函数调用 2 console.log(p2.age);//10 3 console.log(p2.constructor); 4 5 Person(12,"Will",100);//当作普通函数调用 6 console.log(window.age);//12 7 8 var p3=new Object();//另一个对象的作用域调用 9 Person.call(p3,14,"Jessy",80); 10 console.log(p3.age);//14
- 原型模式
- 每个函数都具有原型,在创建新的函数时,JS会隐式的给这个函数创建一个prototype属性,这个属性类似指针,指向函数的原型对象。函数的原型对象具有constructor属性,指向构造这个对象的构造函数。
1 console.log(Person.prototype);//构造函数Person通过prototype指向它的原型。 2 console.log(p2.constructor);//对象p2通过constructor指向它的构造函数Person 3 console.log(Person.prototype.constructor);//又指回了Person.
2. 通过isPrototypeOf和getPrototypeOf来判断对象之间的从属关系。
1 console.log(Person.prototype.isPrototypeOf(p2));//true 2 console.log(Object.getPrototypeOf(p2)==Person.prototype);//true;
3. hasOwnProperty可判断对象是否具有自身的属性,无关原型。delete可删除对象自身的属性,但是无法删除原型的属性。
4. in操作符则可以顺着原型链向上查找,返回布尔值。for-in循环可以返回能够访问的且可枚举的属性,无论实在原型还是实例本身。要想获得对象上所有可枚举的实例属性,使用Object.keys()方法。
1 console.log(Object.keys(p2));//["age", "name", "weight"]
- 定义原型,可以通过更简单的方法。但是要注意重新定义的时候construtor的修改。
1 function Video(){ 2 Video.prototype{ 3 _year:2010, 4 _name:"Forever Love", 5 _Singer:"Jonathan", 6 _Price:120, 7 constructor:Video;//防止用instanceOf的时候无法判断是谁创建的实例 8 } 9 10 } 11 Object.defineProperty(Video.prototype,"constructor"{ 12 enumerable:false, 13 value:Person, 14 })//因为修改了原型中constructor属性,所以重新将enumerable属性设置回false
- 所有原生的引用类型(object, Array, String 等等),都具有原型。并且其方法都已经在原型中定义好了。可以在浏览器控制台看Array.prototype
- 构造函数和原型模式的混合使用:
- 原型模式定义共享的属性,构造函数用于定义实例对象。例如:
1 console.log('Construtor Mode+Prototype Mode:') 2 function Animal(name, age, weight,food){ 3 this.name=name, 4 this.age=age, 5 this.weight=weight, 6 this.food=food 7 } 8 Animal.prototype={ 9 constructor:"Animal", 10 sayName:function(){ 11 alert(this.name); 12 } 13 } 14 var cat=new Animal("mimi",5,20,["fish"]); 15 var dog=new Animal("wawa",6,15,["bone"]); 16 cat.food.push("rat"); 17 console.log(cat.food);//["fish", "rat"] 18 console.log(dog.food);//["bone"] 19 console.log(dog.sayName==cat.sayName);//true
- 寄生构造函数模式
1 //寄生构造模式parasite constrution mode 2 function someone(name, age,job){ 3 var o=new Object(); 4 o.name=name; 5 o.age=age; 6 o.job=job; 7 o.sayName=function(){ 8 console.log(this.name) 9 } 10 return o; 11 } 12 var friend=new someone("JS",12,"hardwork"); 13 friend.sayName();//JS
寄生构造函数模式,除了在函数内部用new新建了一个构造函数以外,其它都和工厂模式一样。
这个模式很有意思,看以下代码:
1 //寄生模式的应用 2 function specialArray(){ 3 var values=new Array();//values相当于构造函数 4 values.push.apply(values,arguments);//给构造函数添加值 5 values.toPipedString=function(){//定义toPipedString方法 6 return values.join("|"); 7 } 8 return values;//返回构造函数 9 } 10 var colors=new specialArray("BLUE","YELLOW","RED");//新建colors对象 11 console.log(colors.toPipedString());//BLUE|YELLOW|RED 调用toPipedString方法
有时候,把function看成JAVA中的class能帮助于理解,呵呵
- 稳妥构造函数的方法
1 //稳妥构造函数模式 2 function People(age,name,job){ 3 var o=new Object(); 4 o.name=name; 5 o.age=age; 6 o.job=job; 7 o.sayName=function(){ 8 return o.name; 9 } 10 return o; 11 } 12 var aMan=new People(20,"Jonathan","Coding"); 13 console.log(aMan.sayName());//Jonathan
这里所谓的稳妥,是指在安全模式下,不用this来构建,并且外部只能通过sayName来访问name这个字段,其他字段初始化之后便不能修改。
浙公网安备 33010602011771号