老生常谈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 相关文章推荐
Javascript实现的类似Google的Div拖动效果代码
Aug 09 Javascript
JS判断、校验MAC地址的2个实例
May 05 Javascript
在JSP中如何实现MD5加密的方法
Nov 02 Javascript
微信小程序 五星评价功能的实现
Mar 09 Javascript
使用jQuery,Angular实现登录界面验证码详解
Apr 27 jQuery
分享19个JavaScript 有用的简写写法
Jul 07 Javascript
input输入框内容实时监测(附代码)
Aug 15 Javascript
详解react-native-fs插件的使用以及遇到的坑
Sep 12 Javascript
node.js学习之事件模块Events的使用示例
Sep 28 Javascript
在vue-cli3.0 中使用预处理器 (Sass/Less/Stylus) 配置全局变量操作
Aug 10 Javascript
Javascript如何实现扩充基本类型
Aug 26 Javascript
JavaScript 异步时序问题
Nov 20 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
Re:从零开始的异世界生活 第2季 开播啦
2020/07/24 日漫
提升PHP执行速度全攻略(下)
2006/10/09 PHP
理解PHP中的stdClass类
2014/04/18 PHP
Yii2实现多域名跨域同步登录退出
2017/02/04 PHP
PHP中的使用curl发送请求(GET请求和POST请求)
2017/02/08 PHP
PHP实现的简单异常处理类示例
2017/05/04 PHP
JavaScript语法着色引擎(demo及打包文件下载)
2007/06/13 Javascript
Javascript 的addEventListener()及attachEvent()区别分析
2009/05/21 Javascript
深入理解JQuery keyUp和keyDown的区别
2013/12/12 Javascript
js冒泡、捕获事件及阻止冒泡方法详细总结
2014/05/08 Javascript
jQuery调取jSon数据并展示的方法
2015/01/29 Javascript
JS插件overlib用法实例详解
2015/12/26 Javascript
详解javascript实现自定义事件
2016/01/19 Javascript
JavaScript 身份证号有效验证详解及实例代码
2016/10/20 Javascript
从零开始学习Node.js系列教程三:图片上传和显示方法示例
2017/04/13 Javascript
easyui datagrid 表格中操作栏 按钮图标不显示的解决方法
2017/07/27 Javascript
React中jquery引用的实现方法
2017/09/12 jQuery
jQuery实现的简单日历组件定义与用法示例
2018/12/24 jQuery
详解easyui 切换主题皮肤
2019/04/04 Javascript
Python实现处理管道的方法
2015/06/04 Python
Python读写docx文件的方法
2018/05/08 Python
Python计算一个给定时间点前一个月和后一个月第一天的方法
2018/05/29 Python
python如果快速判断数字奇数偶数
2019/11/13 Python
Python嵌入C/C++进行开发详解
2020/06/09 Python
英国蛋糕装饰用品一站式商店:Craft Company
2019/03/18 全球购物
MaBelle玛贝尔香港官网:香港钻饰连锁店
2019/09/09 全球购物
趣天网日本站:Qoo10 JP
2019/09/18 全球购物
上海奥佳笔试题面试题
2016/11/16 面试题
致裁判员加油稿
2014/02/08 职场文书
电子专业自荐信
2014/07/01 职场文书
2014年度党员自我评议
2014/09/13 职场文书
2015年电话销售工作总结范文
2015/04/20 职场文书
酒店开业主持词
2015/07/02 职场文书
MySQL 重写查询语句的三种策略
2021/05/10 MySQL
sql server删除前1000行数据的方法实例
2021/08/30 SQL Server
详细聊一聊mysql的树形结构存储以及查询
2022/04/05 MySQL