欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

老生常谈javascript的面向对象思想

程序员文章站 2022-05-14 19:23:06
面向对象的三大基本特性 封装(把相关的信息(无论数据或方法)存储在对象中的能力) 继承(由另一个类(或多个类)得来类的属性和方法的能力) 多态(一个对象在不同情况下的...

面向对象的三大基本特性

封装(把相关的信息(无论数据或方法)存储在对象中的能力)

继承(由另一个类(或多个类)得来类的属性和方法的能力)

多态(一个对象在不同情况下的多种形态)

定义类或对象

第一种:基于object对象

var person = new object();
person.name = "rose";
person.age = 18;
person.getname = function () {
 return this.name;
};
console.log(person.name);//rose
console.log(person.getname);//function () {return this.name;}
console.log(person.getname());//rose
 

缺点:不能创建多个对象。

第二种:基于字面量方式

var person = {
 name : "rose",
 age : 18 ,
 getname : function () {
  return this.name;
 }
};
console.log(person.name);//rose
console.log(person.getname);//function () {return this.name;}
console.log(person.getname());//rose

优点:比较清楚的查找对象包含的属性和方法;

缺点:不能创建多个对象。

第三种:工厂模式

方式一:

function createperson(name,age) {
 var object = new object();
 object.name = name;
 object.age = age;
 object.getname = function () {
  return this.name;
 };
 return object;
}
var person1 = createperson("rose",18);
var person2 = createperson("jack",20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname);//false//重复生成函数,为每个对象都创建独立的函数版本
 

优点:可以创建多个对象;

缺点:重复生成函数getname(),为每个对象都创建独立的函数版本。

方式二:

function createperson(name,age) {
 var object = new object();
 object.name = name;
 object.age = age;
 object.getname = getname;
 return object;
}
function getname() {
 return this.name;
}
var person1 = createperson("rose",18);
var person2 = createperson("jack",20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname);//true//共享同一个函数

优点:可以创建多个对象;

缺点:从语义上讲,函数getname()不太像是person对象的方法,辨识度不高。

第四种:构造函数方式

方式一:

function person(name,age) {
 this.name = name;
 this.age = age;
 this.getname = function () {
  return this.name;
 }
}
var person1 = new person("rose",18);
var person2 = new person("jack",20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname); //false//重复生成函数,为每个对象都创建独立的函数版本

优点:可以创建多个对象;

缺点:重复生成函数getname(),为每个对象都创建独立的函数版本。

方式二:

function person(name,age) {
 this.name = name;
 this.age = age;
 this.getname = getname ;
}
function getname() {
 return this.name;
}
var person1 = new person("rose",18);
var person2 = new person("jack",20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname); //true//共享同一个函数
 

优点:可以创建多个对象;

缺点:从语义上讲,函数getname()不太像是person对象的方法,辨识度不高。

第五种:原型方式

function person() {
}
person.prototype.name = 'rose';
person.prototype.age = 18;
person.prototype.getname = function () {
 return this.name;
};
var person1 = new person();
var person2 = new person();
console.log(person1.name);//rose
console.log(person2.name);//rose//共享同一个属性
console.log(person1.getname === person2.getname);//true//共享同一个函数

缺点:它省略了为构造函数传递初始化参数,这在一定程序带来不便;另外,最主要是当对象的属性是引用类型时,它的值是不变的,总是引用同一个外部对象,所有实例对该对象的操作都会影响其它实例:

function person() {
}
person.prototype.name = 'rose';
person.prototype.age = 18;
person.prototype.lessons = ["语文","数学"];
person.prototype.getname = function () {
 return this.name;
};
var person1 = new person();
person1.lessons.push("英语");
var person2 = new person();
console.log(person1.lessons);//["语文", "数学", "英语"]
console.log(person2.lessons);//["语文", "数学", "英语"]//person1修改影响了person2

第六种:构造函数+原型方式(推荐)

function person(name,age) {
 this.name = name;
 this.age = age;
}
person.prototype.getname = function () {
 return this.name;
};
var person1 = new person('rose', 18);
var person2 = new person('jack', 20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname);//true//共享原型中定义的方法

缺点:属性定义在构造函数内,方法定义在构造函数外,与面向对象的封装思想不符。

第七种:构造函数+动态原型方式(推荐)

方式一:

function person(name,age) {
 this.name = name;
 this.age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person1 = new person('rose', 18);
var person2 = new person('jack', 20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname);//true//共享原型中定义的方法

方式二:

function person(name,age) {
 this.name = name;
 this.age = age;
 if (typeof this.getname !== "function"){
  person.prototype.getname = function () {
   return this.name;
  };
 }
}
var person1 = new person('rose', 18);
var person2 = new person('jack', 20);
console.log(person1.name);//rose
console.log(person2.name);//jack
console.log(person1.getname === person2.getname);//true//共享原型中定义的方法

对象属性的扩展及删除

javascript的对象可以使用 '.' 操作符动态的扩展其属性,可以使用 'delete' 关键字或将属性的值设置为 'undefined' 来删除属性。

function person(name,age) {
 this.name = name;
 this.age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person = new person("rose",18);
person.job = 'engineer';//添加属性
console.log(person.job);//engineer
delete person.job;//删除属性
console.log(person.job);//undefined//删除属性后值为undefined
person.age = undefined;//删除属性
console.log(person.age);//undefined//删除属性后值为undefined

对象属性类型

数据属性

特性:

[configurable]:表示能否使用delete操作符删除从而重新定义,或能否修改为访问器属性。默认为true;

[enumberable]:表示是否可通过for-in循环返回属性。默认true;

[writable]:表示是否可修改属性的值。默认true;

[value]:包含该属性的数据值。读取/写入都是该值。默认为undefined;如上面实例对象person中定义了name属性,其值为'my name',对该值的修改都反正在这个位置

function person(name,age) {
 this.name = name;
 this.age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person = new person("rose",18);
object.defineproperty(person,"name",{configurable:false,writable:false});
person.name = "jack";
console.log(person.name);//rose//重新赋值无效
delete person.name;
console.log(person.name);//rose//删除无效

注意:

一旦将configurable设置为false,则无法再使用defineproperty将其修改为true(执行会报错:cannot redefine property : propertyname)

function person(name,age) {
 this.name = name;
 this.age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person = new person("rose",18);
object.defineproperty(person,"name",{configurable:false,writable:false});
person.name = "jack";
console.log(person.name);//rose//重新赋值无效
delete person.name;
console.log(person.name);//rose//删除无效
object.defineproperty(person,"name",{configurable:true,writable:true});//cannot redefine property: name

访问器属性

特性:

[configurable]:是否可通过delete操作符删除重新定义属性;

[numberable]:是否可通过for-in循环查找该属性;

[get]:读取属性时调用,默认:undefined;

[set]:写入属性时调用,默认:undefined;

访问器属性不能直接定义,必须使用defineproperty()或defineproperties来定义:如下

function person(name,age) {
 this.name = name;
 this._age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person = new person("rose",18);
object.defineproperty(person,"age",{
 get:function () {
  return this._age;
 },
 set:function (age) {
  this._age = age;
 }});
person.age = 20;
console.log(person.age);//20//person.age=20是使用set方法将20赋值给_age,person.age是使用get方法将_age的读取出来
console.log(person._age);//20

获取所有的属性和属性的特性

使用object.getownpropertynames(object)方法可以获取所有的属性;

使用object.getownpropertydescriptor(object,property)方法可以取得给定属性的特性;

function person(name,age) {
 this.name = name;
 this._age = age;
 if (typeof person._getname === "undefined"){
  person.prototype.getname = function () {
   return this.name;
  };
  person._getname = true;
 }
}
var person = new person("rose",18);
object.defineproperty(person,"age",{
 get:function () {
  return this._age;
 },
 set:function (age) {
  this._age = age;
 }});
console.log(object.getownpropertynames(person));//["name", "_age", "age"]
console.log(object.getownpropertydescriptor(person,"age"));//{enumerable: false, configurable: false, get: function, set: function}

对于数据属性,可以取得:configurable,enumberable,writable和value;

对于访问器属性,可以取得:configurable,enumberable,get和set;

继承机制实现

对象冒充

function father(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function son(name,age) {
 this._newmethod = father;
 this._newmethod(name);
 delete this._newmethod;

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var father = new father("tom");
var son = new son("jack",18);
console.log(father.getname());//tom
console.log(son.getname());//jack//继承父类getname()方法
console.log(son.getage());//18

多继承(利用对象冒充可以实现多继承)

function fathera(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function fatherb(job) {
 this.job = job;
 this.getjob = function () {
  return this.job;
 }
}
function son(name,job,age) {
 this._newmethod = fathera;
 this._newmethod(name);
 delete this._newmethod;
 this._newmethod = fatherb;
 this._newmethod(job);
 delete this._newmethod;

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var fathera = new fathera("tom");
var fatherb = new fatherb("engineer");
var son = new son("jack","programmer",18);
console.log(fathera.getname());//tom
console.log(fatherb.getjob());//engineer
console.log(son.getname());//jack//继承父类fathera的getname()方法
console.log(son.getjob());//programmer//继承父类fatherb的getjob()方法
console.log(son.getage());//18
 

call()方法

function father(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function son(name,job,age) {
 father.call(this,name);

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var father = new father("tom");
var son = new son("jack","programmer",18);
console.log(father.getname());//tom
console.log(son.getname());//jack//继承父类getname()方法
console.log(son.getage());//18

多继承(利用call()方法实现多继承)

function fathera(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function fatherb(job) {
 this.job = job;
 this.getjob = function () {
  return this.job;
 }
}
function son(name,job,age) {
 fathera.call(this,name);
 fatherb.call(this,job);

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var fathera = new fathera("tom");
var fatherb = new fatherb("engineer");
var son = new son("jack","programmer",18);
console.log(fathera.getname());//tom
console.log(fatherb.getjob());//engineer
console.log(son.getname());//jack//继承父类fathera的getname()方法
console.log(son.getjob());//programmer//继承父类fatherb的getjob()方法
console.log(son.getage());//18

apply()方法

function father(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function son(name,job,age) {
 father.apply(this,new array(name));

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var father = new father("tom");
var son = new son("jack","programmer",18);
console.log(father.getname());//tom
console.log(son.getname());//jack//继承父类getname()方法
console.log(son.getage());//18

多继承(利用apply()方法实现多继承)

function fathera(name) {
 this.name = name ;
 this.getname = function () {
  return this.name;
 }
}
function fatherb(job) {
 this.job = job;
 this.getjob = function () {
  return this.job;
 }
}
function son(name,job,age) {
 fathera.apply(this,new array(name));
 fatherb.apply(this,new array(job));

 this.age = age;
 this.getage = function () {
  return this.age;
 }
}
var fathera = new fathera("tom");
var fatherb = new fatherb("engineer");
var son = new son("jack","programmer",18);
console.log(fathera.getname());//tom
console.log(fatherb.getjob());//engineer
console.log(son.getname());//jack//继承父类fathera的getname()方法
console.log(son.getjob());//programmer//继承父类fatherb的getjob()方法
console.log(son.getage());//18

原型链方法

function father() {
}
father.prototype.name = "tom";
father.prototype.getname = function () {
 return this.name;
};
function son() {
}
son.prototype = new father();
son.prototype.age = 18;
son.prototype.getage = function () {
 return this.age;
};
var father = new father();
var son = new son();
console.log(father.getname());//tom
console.log(son.getname());//tom//继承父类fathera的getname()方法
console.log(son.getage());//18
 

混合方式(call()+原型链)

function father(name) {
 this.name = name;
}
father.prototype.getname = function () {
 return this.name;
};
function son(name,age) {
 father.call(this,name);
 this.age = age;
}
son.prototype = new father();
son.prototype.getage = function () {
 return this.age;
};
var father = new father("tom");
var son = new son("jack",18);
console.log(father.getname());//tom
console.log(son.getname());//jack//继承父类father的getname()方法
console.log(son.getage());//18

多态机制实现

function person(name) {
 this.name = name;
 if (typeof this.getname !== "function"){
  person.prototype.getname = function () {
   return this.name;
  }
 }
 if (typeof this.toeat !== "function"){
  person.prototype.toeat = function (animal) {
   console.log( this.getname() + "说去吃饭:");
   animal.eat();
  }
 }
}
function animal(name) {
 this.name = name;
 if (typeof this.getname !== "function"){
  animal.prototype.getname = function () {
   return this.name;
  }
 }
}
function cat(name) {
 animal.call(this,name);
 if (typeof this.eat !== "function"){
  cat.prototype.eat = function () {
   console.log(this.getname() + "吃鱼");
  }
 }
}
cat.prototype = new animal();
function dog(name) {
 animal.call(this,name);
 if (typeof this.eat !== "function"){
  dog.prototype.eat = function () {
   console.log(this.getname() + "啃骨头");
  }
 }
}
dog.prototype = new animal();

var person = new person("tom");
person.toeat(new cat("cat"));//tom说去吃饭:cat吃鱼
person.toeat(new dog("dog"));//tom说去吃饭:dog啃骨头

以上这篇老生常谈javascript的面向对象思想就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持。