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


Posted in Javascript onAugust 22, 2017

面向对象的三大基本特性

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

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

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

定义类或对象

第一种:基于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的面向对象思想就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
Locate a File Using a File Open Dialog Box
Jun 18 Javascript
JavaScript的面向对象方法以及差别
Mar 31 Javascript
简介AngularJS的视图功能应用
Jun 17 Javascript
对js eval()函数的一些见解
Aug 15 Javascript
Angular2 环境配置详细介绍
Sep 21 Javascript
详解为Angular.js内置$http服务添加拦截器的方法
Dec 20 Javascript
JS中append字符串包含onclick无效传递参数失败的解决方案
Dec 26 Javascript
解析Vue 2.5的Diff算法
Nov 28 Javascript
深度了解vue.js中hooks的相关知识
Jun 14 Javascript
Vue表单控件数据绑定方法详解
Feb 05 Javascript
jquery实现加载更多"转圈圈"效果(示例代码)
Nov 09 jQuery
微信小程序实现拍照和相册选取图片
May 09 Javascript
使用jQuery实现简单的tab框实例
Aug 22 #jQuery
基于node.js之调试器详解
Aug 22 #Javascript
js获取css的各种样式并且设置他们的方法
Aug 22 #Javascript
简单实现js上传文件功能
Aug 21 #Javascript
不得不看之JavaScript构造函数及new运算符
Aug 21 #Javascript
JavaScript实现简单图片轮播效果
Aug 21 #Javascript
Javascript中 toFixed四舍六入方法
Aug 21 #Javascript
You might like
dedecms模版制作使用方法
2007/04/03 PHP
php格式化日期实例分析
2014/11/12 PHP
Yii框架Session与Cookie使用方法示例
2019/10/14 PHP
用JSON做数据传输格式中的一些问题总结
2011/12/21 Javascript
JavaScript移除数组元素减少长度的方法
2013/09/05 Javascript
jQuery截取指定长度字符串的实现原理及代码
2014/07/01 Javascript
jQuery中siblings()方法用法实例
2015/01/08 Javascript
jquery获取及设置outerhtml的方法
2015/03/09 Javascript
AngularJS使用ngMessages进行表单验证
2015/12/27 Javascript
jQuery插件imgPreviewQs实现上传图片预览
2016/01/15 Javascript
浅谈javascript中执行环境(作用域)与作用域链
2016/12/08 Javascript
微信小程序登录态控制深入分析
2017/04/12 Javascript
React.js中常用的ES6写法总结(推荐)
2017/05/09 Javascript
js封装成插件_Canvas统计图插件编写实例
2017/09/12 Javascript
jQuery选择器之子元素选择器详解
2017/09/18 jQuery
vue父组件向子组件(props)传递数据的方法
2018/01/02 Javascript
使用Vue开发一个实时性时间转换指令
2018/01/17 Javascript
基于vue中对鼠标划过事件的处理方式详解
2018/08/22 Javascript
[03:06]3分钟带你回顾DOTA2完美盛典&完美大师赛
2017/12/06 DOTA
[04:50]2019DOTA2高校联赛秋季赛四强集锦
2019/12/27 DOTA
使用python在本地电脑上快速处理数据
2017/06/22 Python
使用python3实现操作串口详解
2019/01/01 Python
python读取文件名并改名字的实例
2019/01/07 Python
python 实现return返回多个值
2019/11/19 Python
如何实现更换Jupyter Notebook内核Python版本
2020/05/18 Python
Python SMTP配置参数并发送邮件
2020/06/16 Python
LightInTheBox西班牙站点:全球商品在线采购
2016/09/22 全球购物
英国复古服装和球衣购买网站:3Retro Football
2018/07/09 全球购物
装潢设计实习自我鉴定
2013/09/19 职场文书
后勤人员自我评价怎么写
2013/09/19 职场文书
物业管理毕业生的自我评价
2014/02/17 职场文书
开学寄语大全
2014/04/08 职场文书
倡议书的写法
2014/08/30 职场文书
python 定义函数 返回值只取其中一个的实现
2021/05/21 Python
react antd实现动态增减表单
2021/06/03 Javascript
hive数据仓库新增字段方法
2022/06/25 数据库