JavaScript 面向对象(一) —— 基础篇

JavaScript 面向对象(二) —— 案例篇

一、json方式的面向对象

首先要知道,js中出现的东西都能够放到json中。关于json数据格式这里推荐一篇博客:JSON 数据格式

先看下json创建的简单对象:相比基础篇中的构造函数、原型等的创建方式,json方式简单方便;但是缺点很明显,如果想创建多个对象,那么会产生大量重复代码,不可取。

JSON方式适用于只创建一个对象的情况,代码简介又优雅。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script>
var person = {
name: "jiangzhou",
age: 22,
showName: function(){
alert(this); //[Object Object]
alert("姓名:"+this.name);
},
showAge: function(){
alert("年龄:"+this.age);
}
};
person.showName();
person.showAge(); </script>
</head>
</html>

JSON在JS面向对象的应用中,主要的一个作用就是命名空间:如果有大量常用的js函数,利用json,我们可以将同一类函数放在一个“类”里,类似于java那样,这样我们就能很好的管理和查找使用这些js函数,看下面的例子就很好理解了。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title></title>
<script>
//仿java.lang包
var lang = {}; /**
* 仿java.lang.Math类
*/
lang.Math = {
/**
* 求绝对值
* @param {Object} a
*/
abs: function(a){
return a > 0 ? a : -a;
},
/**
* 求最大值
* @param {Object} a
* @param {Object} b
*/
max: function(a, b){
return a > b ? a : b;
},
/**
* PI
*/
PI: 3.1415926
} /**
* 仿java.lang.String类
*/
lang.String = {
/**
* 求字符串长度
* @param {Object} str
*/
length: function(str){
return str.length;
},
/**
* 将字符串转为小写
* @param {Object} str
*/
toLowerCase: function(str){
return str.toLowerCase();
},
/**
* 将字符串转为大写
* @param {Object} str
*/
toUpperCase: function(str){
return str.toUpperCase();
}
} //调用
alert(lang.Math.abs(-19)); //19
alert(lang.Math.PI);
alert(lang.String.toUpperCase("abcdefg")); //ABCDEFG </script>
</head>
</html>

二、面向对象的继承

先举个简单的例子来说一下JS中的继承,Student <extends> Person;

在js中,通过call来调用父类的构造方法继承父类的属性(第33行),通过原型来继承父类的方法(第39行)。注意:先调用父类构造函数,再添加自己的属性;先继承父类的方法,再添加自己的方法。

这里解释下为什么调用Person.call(this, name, sex)就相当于是在调用父类的构造方法:先问一下这个call中的this是谁?这里指向对象student吧。

所以,在子构造函数中调用Person.call()时,那么构造函数Person里的两行代码this.name=name, this.sex=sex中this就是代表student了,所以这两行代码相当于是在为student添加name和sex属性。

但是,下面的通过原型来继承父类的方法,即Student.prototype = Person.prototype,是有问题的,这种方式将影响父类(继承是不能影响父类的),此时Person的原型中有了个showMajor方法(第50行),为什么呢?先思考下,下面解释。

 <!DOCTYPE html>
<html>
<meta charset="UTF-8" />
<head>
<script> /**
* Person 父类 人
* @param {Object} name 姓名
* @param {Object} sex 性别
*/
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.showName = function(){
alert("姓名:"+this.name);
}
Person.prototype.showSex = function(){
alert("性别:"+this.sex);
} /*-----------------------------------------------------*/ /**
* Student 学生 继承 人
* @param {Object} name
* @param {Object} sex
* @param {Object} major 学生特有属性:专业
*/
function Student(name, sex, major){
//调用父类的构造函数
Person.call(this, name, sex); //添加自己的属性
this.major = major;
}
//继承父类原型中的方法
Student.prototype = Person.prototype;
//添加自己特有的方法
Student.prototype.showMajor = function(){
alert("专业:"+this.major);
} var student = new Student("bojiangzhou", "男", "信息管理");
student.showName();
student.showSex();
student.showMajor(); alert(Person.prototype.showMajor);
</script>
</head>
</html>

第50行弹出的信息:

为了解释为什么通过Student.prototype = Person.prototype来继承父类的方法会影响父类,下面举一个数组的例子,一看就知道怎么回事了。

为什么arr1和arr2弹出来的一样呢?第15、16行显示arr1和arr2是一个对象。对象!应该很清楚了吧,arr1和arr2都是指向这个数组对象的一个引用,所以改变arr2时,arr1也变了。

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<script>
var arr1 = [1,2,3,4,5];
var arr2 = arr1; arr2.push(6); alert(arr1); //弹出1,2,3,4,5,6
alert(arr2); //弹出1,2,3,4,5,6 alert(typeof arr1); //object
alert(typeof arr2); //object
</script>
</html>

其实我们主要是想获得arr1数组的一个副本,怎么做才能不改变arr1呢,看下面:

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<script>
var arr1 = [1,2,3,4,5];
var arr2 = []; //复制arr1的数据即可
for(var i=0;i<arr1.length;i++){
arr2[i]=arr1[i];
} arr2.push(6); alert(arr1); //弹出1,2,3,4,5
alert(arr2); //弹出1,2,3,4,5,6 </script>
</html>

同样的,我们也可以通过这种方式为继承的子类添加父类原型中的方法,而又不影响父类(38-41行):

 <!DOCTYPE html>
<html>
<meta charset="UTF-8" />
<head>
<script> /**
* Person 父类 人
* @param {Object} name 姓名
* @param {Object} sex 性别
*/
function Person(name, sex){
this.name = name;
this.sex = sex;
}
Person.prototype.showName = function(){
alert("姓名:"+this.name);
}
Person.prototype.showSex = function(){
alert("性别:"+this.sex);
} /*-----------------------------------------------------*/ /**
* Student 学生 继承 人
* @param {Object} name
* @param {Object} sex
* @param {Object} major 学生特有属性:专业
*/
function Student(name, sex, major){
//调用父类的构造函数
Person.call(this, name, sex); //添加自己的属性
this.major = major;
}
//继承父类原型中的方法
for(var p in Person.prototype){
Student.prototype[p] = Person.prototype[p];
} //添加自己特有的方法
Student.prototype.showMajor = function(){
alert("专业:"+this.major);
} var student = new Student("bojiangzhou", "男", "信息管理");
student.showName();
student.showSex();
student.showMajor(); alert(Person.prototype.showMajor);
</script>
</head>
</html>

第53行弹出信息:Person中没有showMajor方法了。

最后,以案例篇中最后给出的拖拽例子来应用下继承,那个拖拽有一个问题,就是没有控制拖拽出边界的问题。

先贴出之前的拖拽版本:

drag.js:

 /**
* 拖拽
* @param {Object} id div的id
*/
function Drag(id){
this.oBox = document.getElementById(id);
this.disX = 0;
this.disY = 0; var _this = this; this.oBox.onmousedown = function(){
_this.fnDown();
}
}
//鼠标按下
Drag.prototype.fnDown = function(ev){
var oEvent = ev || event; this.disX = oEvent.clientX - this.oBox.offsetLeft;
this.disY = oEvent.clientY - this.oBox.offsetTop; var _this = this; document.onmousemove = function(){
_this.fnMove();
};
document.onmouseup = function(){
_this.fnUp();
};
}
//鼠标移动
Drag.prototype.fnMove = function(ev){
var oEvent= ev || event; this.oBox.style.left = oEvent.clientX - this.disX + 'px';
this.oBox.style.top = oEvent.clientY - this.disY + 'px';
}
//鼠标抬起
Drag.prototype.fnUp = function(){
document.onmousemove = null;
document.onmouseup = null;
}

drag.html:

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
div {
position: absolute;
}
</style>
<title>拖拽</title>
<script type="text/javascript" src="../js/drag.js" ></script>
<script>
window.onload = function(){
var drag1 = new Drag("box1"); var drag1 = new Drag("box2");
};
</script>
</head> <body>
<div id="box1" style="background: red;width: 200px;height: 200px;"></div> <div id="box2" style="background: blue;width: 100px;height: 300px;"></div>
</body>
</html>

效果:可以看到红色和蓝色的都出边界了,但我们又不想去修改代码,那我们怎么做?学过java的应该都知道可以写一个子类来做一些更加具体的操作,又保留了父类的功能,就是继承。

DragLimit.js:DragLimit继承自Drag,控制了不能出边界

 /**
* 限制边界的拖拽,继承自Drag
* @param {Object} id
*/
function DragLimit(id){
Drag.call(this, id);
}
//继承方法
for(var p in Drag.prototype){
DragLimit.prototype[p] = Drag.prototype[p];
}
/**
* 覆写父类的鼠标移动方法,控制不能移出边界
*/
DragLimit.prototype.fnMove = function(ev){
var oEvent= ev || event; var left = oEvent.clientX - this.disX;
var top = oEvent.clientY - this.disY; //控制边界
if(left < 0){
left = 0;
} else if(left > document.documentElement.clientWidth-this.oBox.offsetWidth){
left = document.documentElement.clientWidth-this.oBox.offsetWidth;
}
if(top <= 0){
top = 0;
} else if(top > document.documentElement.clientHeight-this.oBox.offsetHeight){
top = document.documentElement.clientHeight-this.oBox.offsetHeight;
} this.oBox.style.left = left + 'px';
this.oBox.style.top = top + 'px';
}

dragLimit.html

 <!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
padding: 0;
margin: 0;
}
div {
position: absolute;
}
</style>
<title>拖拽</title>
<script type="text/javascript" src="../js/drag.js" ></script>
<script type="text/javascript" src="../js/dragLimit.js" ></script>
<script>
window.onload = function(){
var drag1 = new Drag("box1"); var drag1 = new DragLimit("box2");
};
</script>
</head> <body>
<div id="box1" style="background: red;width: 200px;height: 200px;"></div> <div id="box2" style="background: blue;width: 100px;height: 300px;"></div>
</body>
</html>

效果:蓝色是不能移出边界的。

 三、JS中的对象

js中的对象分为本地对象、内置对象、宿主对象,这里给出W3School文档供参考:ECMAScript 对象类型

JavaScript 面向对象(三) —— 高级篇的更多相关文章

  1. JavaScript 面向对象(二) —— 案例篇

    看案例前可以先看看基础篇:JavaScript 面向对象(一) —— 基础篇 案例——面向对象的选项卡:把面向过程的程序一步步改成面向对象的形式,使其能够更加的通用(但是通用的东西,一般会比较臃肿). ...

  2. JavaScript 面向对象(一) —— 基础篇

    学好JS的面向对象,能很大程度上提高代码的重用率,像jQuery,easyui等,这篇博客主要从细节上一步步讲JS中如何有效地创建对象,也可以看到常见的创建对象的方式,最后也会附上一些JS面向对象的案 ...

  3. javascript面向对象系列第一篇——构造函数和原型对象

    × 目录 [1]构造函数 [2]原型对象 [3]总结 前面的话 一般地,javascript使用构造函数和原型对象来进行面向对象编程,它们的表现与其他面向对象编程语言中的类相似又不同.本文将详细介绍如 ...

  4. javascript面向对象创建高级 Web 应用程序

       目录 JavaScript 对象是词典 JavaScript 函数是最棒的 构造函数而不是类 原型 静态属性和方法 闭包 模拟私有属性 从类继承 模拟命名空间 应当这样编写 JavaScript ...

  5. JavaScript面向对象(三)——继承与闭包、JS实现继承的三种方式

      前  言 JRedu 在之前的两篇博客中,我们详细探讨了JavaScript OOP中的各种知识点(JS OOP基础与JS 中This指向详解 . 成员属性.静态属性.原型属性与JS原型链).今天 ...

  6. javascript面向对象(三):非构造函数的继承

    本文来自阮一峰 这个系列的第一部分介绍了"封装",第二部分介绍了使用构造函数实现"继承". 今天是最后一个部分,介绍不使用构造函数实现"继承" ...

  7. javascript面向对象系列第二篇——创建对象的5种模式

    × 目录 [1]字面量 [2]工厂模式 [3]构造函数[4]原型模式[5]组合模式 前面的话 如何创建对象,或者说如何更优雅的创建对象,一直是一个津津乐道的话题.本文将从最简单的创建对象的方式入手,逐 ...

  8. javascript面向对象(三)

    主要内容: 利用原型链的方式实现继承: 原型继承的特点:即继承了父类的模板,也继承了父类的原型对象. 类继承:只继承模板(借用构造函数的方式继承). 利用call.apply方法实现: 混合继承: 扩 ...

  9. javascript面向对象系列第三篇——实现继承的3种形式

    × 目录 [1]原型继承 [2]伪类继承 [3]组合继承 前面的话 学习如何创建对象是理解面向对象编程的第一步,第二步是理解继承.本文是javascript面向对象系列第三篇——实现继承的3种形式 [ ...

随机推荐

  1. Windows7+32位,MongoDB安装

    在网上找了各种安装MongoDB的教程,总是会出现一些bug,就自己总结了,亲测正确,MongoDB的安装再也不是一件麻烦的事情了~ 1.下载好跟自己电脑适合的安装包,选择Custom自定义安装,将安 ...

  2. 使SWT/JFace支持跨平台

    由于SWT的实现机制,在不同平台下,必须引用不同swt*.jar. 由于这个瓶颈,我们要为不同的平台编译不同的版本.但是这是可以避免的.这将是本文要讨论的内容. 我一共google到了3种soluti ...

  3. WebForm基础

    客户端与网页端: C/S(客户端): 两种方式:winform WPF 数据是存在其它的电脑上或服务器上 运行时需要从服务器上下载相应的数据 数据加工的过程是在用户电脑上执行 好处是数据请求速度比较快 ...

  4. UVA 11210 中国麻将

    https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...

  5. 新接触PHP课程,给自己定制的目标

    PHP课程初接触,对自己的计划和展望恢复 从今天开始了为期四个半月的关于PHP课程的学习.从零开始接触一门新的技术知识,而且还是在短短四个月内就要掌握牢固,其实确确实实感觉不易.可是世间再没有路,不还 ...

  6. 读《编写可维护的JavaScript》第五章总结

    第五章 UI层的松耦合 5.1 什么是松耦合 在Web开发中,用户界面是由三个彼此隔离又相互作用的层定义的: HTML是用来定义页面的数据和语义 CSS用来给页面添加样式 JavaScript用来给页 ...

  7. es6还欠完善的地方

    const的可变性 const用于声明常量. 什么是常量,声明后的值不可更改. 对于值类型,比如string,number等等.const声明确实有效. const str = "strin ...

  8. [linux] scp无密码拷贝

    源服务器为s,ip为111.111.111.112. 目标服务器为d, ip为111.111.111.111 1>在源服务器新建用户 test_s, useradd test_s -g user ...

  9. Ios8代码关闭输入预测问题

    自IOS8出来了输入预测问题后,有些问题也就来了比如textfield中输入邮箱的话,就会有很多空格无法去掉,当时我一直在找有没有提供什么方法可以关闭:后面有这样的一个属性可以解决输入邮箱没有空格问题 ...

  10. C#利用服务器实现客户端之间通信

    这两天在学习C#,C#高级编程真的是厚厚的一本书QAQ. 昨天看了一下里面的通信部分(其实还没怎么看),看了网上一些人的博客,自己在他们的博客基础上写了一个通信. 先来讲述下我自己对于整个Socket ...