引言
面向对象的程序设计
理解对象
对象主要包括
数据属性和访问器
- 简单创建一个对象
var person=new Object();
person.name="zhangsan";
person.age=24;
person.job="IT";
person.sayName=function(){
console.log("人员名:"+person.name);
}
person.sayName();
//打印结果
人员名:zhangsan
-
对象里的数据属性:
Configurable,Enumerable,Writable,Value1.
Configurable: 是否可以删除对象的属性,默认为true.2.
Enumberable: 是否可以通过for-in循环返回属性,默认为true.3.
Writable: 是否可以修改属性的值,默认为true.4.
Value:保存属性值,读取和修改属性值都从这个位置,默认为undefined.
var person={};
Object.defineProperty(person,'name',{writable:false,value:"zhangsan"});
console.log("修改前:"+person.name);
person.name="lisi";
console.log("修改后:"+person.name);
var person={};
Object.defineProperty(person,'name',{configurable:false,value:"zhangsan"});
delete person.name;
//删除操作会报错
//重新设置configurable为true也会报错,也就说只能设置一次
-
访问器的属性:
Configurable,Enumberable,Get,Set,主要介绍Get,SetGet: 调用该函数获取属性值,函数也是一种变量,默认为undefined.Set: 调用该函数设置属性值,默认为undefined.
var book={_year:2004,edition:1};
Object.defineProperty(book,"year",{
get:function(){
return this._year;
},
// set:function(newValue){
// if(newValue>2004){
// this._year=newValue;
// this.edition+=1;
// }
// }
})
book.year=2005;
console.log("没修改成功:"+book.year);
console.log(book.edition);
//打印结果
没修改成功:2004
1
私以为和Writable和Value,区别在于不仅能修改自身的值,还能关联修改其他属性的值。
- 同时定义多个属性值,用
Object.defineProperties设置,可以通过
var book={};
Object.defineProperties(book,{
year:{value:25},
name:{
get:function(){
return "张三";
}
}
})
- 读取属性的特性值:
Object.getOwnPropertyDescriptor,传入两个参数:对象,属性名,根据属性名不同获取的是数据属性或者访问器属性.
var book={};
Object.defineProperties(book,{
year:{value:25},
name:{
get:function(){
return "张三";
}
}
});
var data=Object.getOwnPropertyDescriptor(book,"name");
console.log("获取姓名:"+data.get());
var param=Object.getOwnPropertyDescriptor(book,"year");
console.log("获取年龄:"+param.value);
//打印结果
获取姓名:张三
获取年龄:25
创建对象
- 工厂模式: 无法用
instanceOf判断类型
function createPerson(name,age){
var person=new Object();
person.name=name;
person.age=age;
person.sayName=function(){
console.log(this.name);
}
return person;
}
var person1=createPerson("zhangsan",25);
console.log("姓名:"+person1.name);
//打印结果
姓名:zhangsan
- 构造函数的模式: 函数命令格式为
大驼峰方式
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=function(){
console.log(this.name);
}
}
var person1=new Person("zhangsan",58);
console.log(person1.name);
//打印结果
zhangsan
创建的对象都是不同的,并且可以用instanceOf判断类型
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=function(){
console.log(this.name);
}
}
var person1=new Person("zhangsan",58);
var person2=new Person("zhangsan",58);
console.log(person1==person2);
console.log(person1 instanceof Person)
//打印结果
false
true
这样每次创建的对象里的函数都是不同的,而执行功能的函数没必要不相同,可以把函数抽取出来
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=sayName;
}
function sayName(){
console.log(this.name);
}
var person1=new Person("zhangsan",58);
var person2=new Person("zhangsan",58);
console.log(person1.sayName==person2.sayName);
//打印结果
true
- 原型模式
- 只要创建了一个函数,就会根据
特定规则为函数生成一个prototype属性,该属性指向原型对象
function Person(){
}
Person.prototype.name="zhang san";
Person.prototype.age=15;
Person.prototype.job="IT";
Person.prototype.sayName=function(){
console.log(this.name);
}
var person1=new Person();
var person2=new Person();
console.log(person1.sayName=person2.sayName)
//打印结果
true
- 而在
默认情况下,每个原型对象都会自动获得一个constructor属性,该属性指向prototype 属性所在函数,图解如下:
function Person(){
}
Person.prototype.name=zhangsan;
Person.prototype.age=15;
Person.prototype.job="IT";
Person.prototype.sayName=function(){
console.log(this.name);
}
var person1=new Person();
var person2=new Person();
console.log("person2的原型是否是Person的原型:"+(Object.getPrototypeOf(person2)==Person.prototype));
console.log("person2的name的值:"+Object.getPrototypeOf(person2).name);
//打印结果
true
person2的name的值:zhangsan
- 每当代码
读取对象的某个属性时,会先在对象实例本身查找,如果找不到再顺着原型链去查找.
function Person(){
}
Person.prototype.name="zhangsan";
var person1=new Person();
var person2=new Person();
person1.name="lisi";
console.log("person1 name重新赋值:"+person1.name);
console.log("person2 name未操作:"+person2.name);
//打印结果
person1 name重新赋值:lisi
person2 name未操作:zhangsan
- 判断
实例中是否包含某个属性
function Person(){
}
Person.prototype.name="zhangsan";
var person1=new Person();
console.log("person1是否包含name属性:"+(person1.hasOwnProperty("name")));
person1.name="lisi";
console.log("person1是否包含name属性:"+(person1.hasOwnProperty("name")));
//打印结果
person1是否包含name属性:false
person1是否包含name属性:true
- 判断
实例或者原型中是否包含某个属性
function Person(){
}
Person.prototype.name="zhangsan";
function hasOwnPrototypeProperty(object,prop){
return !object.hasOwnProperty(prop)&& (prop in object);
}
var person1=new Person();
console.log("原型中含有实例中不含有:"+hasOwnPrototypeProperty(person1,"name"));
person1.name="lisi";
console.log("实例中含有:"+ person1.hasOwnProperty("name"));
- 获取对象上可枚举的所有实例属性:
Object.keys(),传入原型对象时获取的是原型对象的属性,传入实例对象获取的是实例对象独有的属性。
function Person(){
}
Person.prototype.name="zhangsan";
Person.prototype.age=25;
Person.prototype.job="IT";
var person=new Person();
person.score=58;
var prop=Object.keys(Person.prototype);
console.log("原型对象属性:"+prop);
var props=Object.keys(person);
console.log("实例对象属性:"+props);
//打印结果
原型对象属性:name,age,job
实例对象属性:score
- 获取
不可枚举属性,感觉有点像java的反射和暴力反射:Object.getOwnPropertyNames()传统对象定义不可枚举
var person={
};
Object.defineProperty(person,"name",{
enumerable:false, //不可枚举
value:"zhangsan",
});
Object.defineProperties(person,{
age:{
enumerable:false, //不可枚举
get:function(){
return 24;
}
},
job:{
get:function(){
return "IT";
}
}
});
var prop=Object.getOwnPropertyNames(person);
console.log(prop);
//打印结果
[ 'name', 'age', 'job' ]
原型模式定义不可枚举
function Person(){
}
Person.prototype.name="zhangsan";
Person.prototype.age=16;
var person=new Person();
Object.defineProperty(person,"job",{
enumerable:false,
value:"IT"
})
var props=Object.getOwnPropertyNames(person);
console.log("实例属性:"+props);
var prop=Object.getOwnPropertyNames(Person.prototype);
console.log("原型属性:"+prop);
//打印结果
实例属性:job
原型属性:constructor,name,age
- 以
字面量的形式定义原型对象,此时必须特别定义原型对象constructor属性的指向,并不会自动生成
function Person(){
}
Person.prototype={
constructor:Person,
name:"zhangsan",
age:24,
sayName:function() {
console.log(this.name);
}
}
var person=new Person();
console.log(person.sayName())
//打印对象
zhangsan
undefined
true
组合使用构造函数模式和原型模式
function Person(name,age){
this.name=name;
this.age=age;
this.sayName=function(){
console.log(this.name);
}
}
Person.prototype={
job:"IT",
friend:"Many",
}
var person=new Person("zhangsan",25);
person.sayName();
console.log(person.job);
//打印结果
zhangsan
IT
动态原型模式
function Person(name,age){
this.name=name;
this.age=age;
if(typeof this.sayName!="function"){
Person.prototype.sayName=function(){
console.log(this.name);
}
}
}
var person=new Person("LISI",26);
person.sayName()
//打印结果
LISI
这里是对原型进行修改,会反馈到所有实例上
寄生构造函数模式
function SpecialArray(){
var arr=new Array();
arr.push.apply(arr,arguments);
arr.toPipeString=function(){
return this.join("|");
}
return arr;
}
var specialArray=new SpecialArray("lisi","wanger","hehe");
console.log(specialArray.toPipeString());
//打印结果
lisi|wanger|hehe
写法类似上面的工厂模式,基本上使用的都是另外一个对象,只对一些实现细节进行修改
稳妥构造函数模式
function Person(name,age,job){
var object=new Object();
object.sayName=function(){
console.log(name);
}
return object;
};
var person=new Person("张三",25,26);
person.sayName();
person.getAge=function(){
console.log(age);
};
person.getAge();
//打印结果
张三
ReferenceError: age is not defined
定义的是稳妥对象:指的是没有公共属性,而且其方法也不引用 this 的对象,对象进行添加属性和方法时也无法获取构造函数传入的原始数据值。