JavaScript对象入门指南
前言
不少开发对JavaScript实现面向对象编程存在一知半解,并且不少的在项目实践中写的都是面向过程编程的代码,因此,希望能从零入手介绍面向对象的一些概念到实现简单的面向对象的例子让大家包括我自己加深对面向对象的认知。硬文一篇,希望能对大家有帮助 ^v^
对象基础
概念
对象是一个包含相关数据和方法的集合,是通过变量和函数组成,通常被我们说成属性和方法,常用对象字面量的形式表示。
创建方法
1.初始化对象
var person={}
2.添加属性(变量)和方法(函数)
var person={
name:'aaron',
say:function(){
alert('hello')
}
}
3.获取属性和执行方法
person.name
person.say()
备注:获取属性和执行方法有两种方法,就是说我上面列举的其一:点表示法,还有一种就是括号表示法。如下:
person['name']
person['say']()
因此,有时对象也被叫做关联数组,即对象做了字符串到值的映射,而数组做的是数字到值的映射。
4.运行截图
5.设置对象成员

备注:有一点需要了解到的是,括号表示法能做到通过定义变量名的方式去设置对象成员,而这一点是点表示法没法实现的。
6.“this”的含义
this的指向其实是一直都让开发者头大的问题了,尤其是后端写JS时。其实说白了this就是指向了当前代码运行时的对象。
例如:


由于对象字面量执行的是当前对象,所以this指向了person。而像创建的构造函数等this的指向就是构造函数实例对象了
优点
一目了然,对象字面量创建的对象的好处可以有效的把对象关联的属性和方法统一了起来,也减少了全局变量的污染,得到一定程度的安全(减少了定义全变量覆盖对象属性的危险)。
面向对象--构造函数
了解OOP思想
例如从现实世界的某个实例出发,对于一个人(person)来说,我们能在他们身上获取到很多信息(他们的住址,身高,鞋码等等),然后我们会基于这些信息介绍关于他们,并需要他们做出回应。而在面向对象的语言中,我们就可以通过类(class)的概念去描述一个对象,而这个类就是定义对象特质的模板。通过创建的class,我们就可以基于它来创建一些拥有class中属性和方法的对象,即实例对象。而这些实例对象一般是具体的人,例如老师,学生。在OOP中,我们也可以基于这个class,创建其他的新类,而这些新的子类(例如家长)可以继承它们父类的属性(数据)和方法(功能),来使用父对象共有的功能。
因此,通过对泛指人到具体的某个学生/老师的关系,我们就可以总结到面向对象的三个基本特性:封装,继承,多态。
引入概念
通过了解面向对象编程(OOP)的基本概念,什么是对象和对象的属性,方法,并了解实现面向对象编程的基本特性。也了解常用的创建对象方法--对象字面量,我们已经对对象的基本概念有了了解。但是,通过对象字面量来创建的只是单一的实体类,并不能实现通用对象(现实模型)的封装,即真正的实现面向对象。
JavaScript是通过构建函数的方式来定义对象和特征的,而构建的实例对象也有通过原型链的方式来继承某些特性。
从实例中学习构建函数和对象实例
1.Person()构造函数,创建实例对象并访问属性和方法:

2.其他创建对象实例的姿势
1.Object()构造函数
var person1=new Object();
person1.name='ace';
person1.age=30;
person1.greeting=function(){
alert('Hi! I\'m ' + this.name + '.'')
}
2.使用create():这样就可以基于person1创建与person1具有相同属性和方法的对象。
var person2=Object.create(person1);
面向对象--对象原型
引入概念
JavaScript的继承机制是有别于其他经典的面向对象编程语言的,是通过原型来实现从其他对象继承功能特性的。
因此,JavaScript常被描述为基于原型的语言--每个对象拥有一个原型对象,对象以其原型为模板、从原型继承方法和属性,原型对象也有可能拥有原型,从中继承方法和属性,以此类推。而这种关系被称为原型链。
我们需要知道的是,这些属性和方法是定义在实例的构造函数上的prototype属性,当然,实例对象也__proto__属性,是从构造函数的prototype属性派生的,即实例对象.__proto===构造函数.prototype。
理解原型对象

从截图我们看到,person1实例除了具有Person()构造器中的属性方法外,还具有其他属性和方法,而这些则是Person()构造器原型对象Object上的成员。

通过调用valueOf,因此,我们也了解到了调用方法的过程:
1.浏览器首先检查,person1 对象是否具有可用的 valueOf() 方法。
2.如果没有,则浏览器检查 person1 对象的原型对象(即 Person)是否具有可用的 valueof() 方法。
3.如果也没有,则浏览器检查 Person() 构造器的原型对象(即 Object)是否具有可用的 valueOf() 方法。Object 具有这个方法,于是该方法被调用。
prototype属性
通过对valueOf方法的调用过程,我们也就了解到了那些能被继承的属性和方法(对象中存在不能被继承的属性方法,例is()/keys())是定义在prototype属性上的。因此,在构造函数是需要被子类继承的属性方法需要定义在prototype上。
constructor属性
每个实例对象都有constructor属性,它是指向创建该实例的构造函数。
而我们也可以通过在constructor后添加()形式实现创建新实例。
修改原型

通过截图我们可以了解到了,虽然已经创建了实例对象person1,当时之后再像构造器Person()prototype中添加方法,person1还是能调用,这就说明了函数调用会通过上溯原型链,从上游对象中调用方法。

如图,若在prototype上定义属性的话,则this的当前执行环境为全局,返回的为undefined。并且,在对象继承上看,一般的做法是在构造器中定义属性,在prototype属性中定义方法。
小demo--实例理解JavaScript中的继承
1.创建构造器Person并在构造器上定义方法
function Person(first, last, age, gender, interests) {
this.name = {
first,
last
};
this.age = age;
this.gender = gender;
this.interests = interests;
};
Person.prototype.bio = function() {
alert(this.name.first + ' ' + this.name.last + ' is ' + this.age + ' years old. He likes ' + this.interests[0] + ' and ' + this.interests[1] + '.');
};
Person.prototype.greeting = function() {
alert('Hi! I\'m ' + this.name.first + '.');
};
2.创建Teacher类Teacher构造器,并继承Person的所有成员,同时具备自有属性和方法:subject,greeting()
function Teacher(first, last, age, gender, interests, subject) {
Person.call(this, first, last, age, gender, interests);
this.subject = subject;
}
3.设置Teacher()的原型和构造器引用

如图,创建的新的Teacher()构造器只有一个空的原型属性,则需从Person()的原型prototype中继承方法:
Teacher.prototype = Object.create(Person.prototype);

如图,我们又遇到了个问题,由于我们创建Teacher的prototype的方式,Teacher()构造器的prototype属性执行了Person(),因此,我们需要设置指向Teacher:
Teacher.prototype.constructor = Teacher;
通过这样,我们就能实现了需要继承的方法都定义在了构造器的prototype属性内,这样才不会打乱了类继承结构。
4.向Teacher()添加新的greeting方法
Teacher.prototype.greeting = function() {
var prefix;
if(this.gender === 'male' || this.gender === 'Male' || this.gender === 'm' || this.gender === 'M') {
prefix = 'Mr.';
} else if(this.gender === 'female' || this.gender === 'Female' || this.gender === 'f' || this.gender === 'F') {
prefix = 'Mrs.';
} else {
prefix = 'Mx.';
}
alert('Hello. My name is ' + prefix + ' ' + this.name.last + ', and I teach ' + this.subject + '.');
};
5.最后运行创建teacher实例,我们就能得到了从Person()构造器继承的属性和方法,并具有只有Teacher()的构造器才有的属性方法。
6.对象成员
通过学习,我们可以知道一般对象所具有的对象成员包括三类:
1.那些定义在构造器函数中的、用于给予对象实例的。一般为对象属性。
2.那些直接在构造函数上定义、仅在构造函数上可用的。这些通常仅在内置的浏览器对象中可用,并通过被直接链接到构造函数而不是实例来识别。 例如Object.keys()。
3.那些在构造函数原型上定义、由所有实例和对象类继承的。一般为对象方法。
深入--设计模式原则
当然,通过上述的方法我们可以实现了基本的面向对象的编程,但是,要实现更高级的类库封装和框架实现,则需要能对设计模式有很好的认知。
在这,我就列举下设计模式原则,希望大家包括我自己有学习的方向。一般的设计原则为:
1.单一职责原则
2.里氏替换原则
3.依赖倒置原则
4.接口隔离原则
5.迪米特原则
6.开闭原则
当然,还有关于面向对象的设计模式(23种),则需要深入了解了,其实这已经是有深入到我们自己的代码中了,只是我们对它的认知并不深。这个就后续了解了~~~
实战:构建对象--弹跳球(ES6实现)
背景
通过对面向对象基本概念,面向对象的编程思想和构造器,原型实现方法实现一个简单的弹跳球小游戏。
介绍
主要通过ES6,class语法糖,通过canvas绘制背景并控制evil的上下左右,吃掉小球。
上代码
1.index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Bouncing balls</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<canvas></canvas>
<script src="mainUpgrade.js"></script>
</body>
</html>
2.mainUpgrade.js
const canvas=document.querySelector('canvas');
const ctx=canvas.getContext('2d');
const width=canvas.width=window.innerWidth;
const height=canvas.height=window.innerHeight;
//create a random number between min and max.
random=(min,max)=>{
let num=Math.floor(Math.random()*(max-min+1))+min;
return num;
};
//create constructor for ball
class Shape{
constructor(x,y,velX,velY,exists){
this.x=x;
this.y=y; //坐标
this.velX=velX;
this.velY=velY; //水平和竖直速度
this.exists=exists; //是否存在
}
}
class Ball extends Shape{
constructor(x,y,velX,velY,exists,color,size){
super(x,y,velX,velY,exists);
this.color=color;
this.size=size;
}
// draw ball
draw (){
ctx.beginPath();
ctx.fillStyle=this.color;
ctx.arc(this.x,this.y,this.size,0,2*Math.PI); // arc()绘制圆弧
ctx.fill();
}
//update ball location
update (){
if((this.x + this.size)>=width){
this.velX=-(this.velX)
}
if((this.x - this.size)<= 0){
this.velX=-(this.velX)
}
if((this.y + this.size)>= height){
this.velY=-(this.velY)
}
if((this.y - this.size)<= 0){
this.velY=-(this.velY)
}
this.x+=this.velX;
this.y+=this.velY;
}
//spy collision
collisionDetect (){
for(let j=0;j<balls.length;j++){
if(!(this===balls[j])){
const dx=this.x - balls[j].x;
const dy=this.y - balls[j].y;
const distance=Math.sqrt(dx*dx + dy*dy);
if(distance<this.size + balls[j].size){
balls[j].color=this.color='rgb('+random(0,255)+','+random(0,255)+','+random(0,255)+')';
}
}
}
}
}
//create evil circle
class EvilCircle extends Shape{
constructor(x,y,exists){
super(x,y,exists);
this.color='white';
this.size=10;
this.velX=20;
this.velY=20;
}
draw(){
ctx.beginPath();
ctx.strokeStyle=this.color;
ctx.lineWidth=3;
ctx.arc(this.x,this.y,this.size,0,2*Math.PI);
ctx.stroke();
}
//check evil location
checkBounds(){
if((this.x + this.size)>width){
this.x-=this.size
}
if((this.y + this.size)>height){
this.y-=this.size
}
if((this.x - this.size)<0){
this.x+=this.size;
}
if((this.y - this.size)<0){
this.y+=this.size;
}
}
setControls(){
window.onkeydown=(e)=>{
if(e.keyCode===38){
this.y-=this.velY
}
else if(e.keyCode===40){
this.y+=this.velY;
}
else if(e.keyCode===37){
this.x-=this.velX
}
else if(e.keyCode===39){
this.x+=this.velX
}
}
}
collisionDetect(){
for(let i=0;i<balls.length;i++){
if(balls[i].exists){
const dx=this.x-balls[i].x;
const dy=this.y-balls[i].y;
const distance=Math.sqrt(dx*dx+dy*dy);
if(distance<this.size+balls[i].size){
balls[i].exists=false;
}
}
}
}
}
let balls=[];
const evil=new EvilCircle(
random(0,width),
random(0,height),
true
);
loop=()=>{
ctx.fillStyle='rgba(0,0,0,0.25)';
ctx.fillRect(0,0,width,height);
while (balls.length < 25){
const ball=new Ball(
random(0,width),
random(0,height),
random(-7,7),
random(-7,7),
true,
'rgb('+ random(0,255)+','+random(0,255)+','+random(0,255)+')',
random(10,20)
);
balls.push(ball);
}
for(let i=0;i<balls.length;i++){
if(balls[i].exists){
balls[i].draw();
balls[i].update();
balls[i].collisionDetect();
}
}
evil.draw();
evil.checkBounds();
evil.setControls();
evil.collisionDetect();
window.requestAnimationFrame(loop) //执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画
}
loop();
运行截图

总结
通过该博文,希望能让大家对了解JavaScript实现面向对象有个基本的了解和概念。如有描述不当的地方望能指出,谢谢。
JavaScript对象入门指南的更多相关文章
- AngularJS快速入门指南07:Http对象
$http是AngularJS提供的一个服务,用来从远程服务器读取数据. 提供数据 下面的数据由Web服务器提供: { "records": [ { "Name" ...
- JavaScript对象属性的基础教程指南
JavaScript是使用“对象化编程”的,或者叫“面向对象编程”的.所谓“对象化编程”,意思是把JavaScript能涉及的范围划分成大大小小的对象,对象下面还继续划分对象直至非常详细为止,所有的编 ...
- TypeScript入门指南(JavaScript的超集)
TypeScript入门指南(JavaScript的超集) 你是否听过 TypeScript? TypeScript 是 JavaScript 的超集,TypeScript结合了类型检查和静态分析 ...
- 深入理解javascript对象系列第二篇——属性操作
× 目录 [1]查询 [2]设置 [3]删除[4]继承 前面的话 对于对象来说,属性操作是绕不开的话题.类似于“增删改查”的基本操作,属性操作分为属性查询.属性设置.属性删除,还包括属性继承.本文是对 ...
- Webpack 入门指南 - 2.模块
这一次我们谈谈模块问题. 通常我们希望这个项目可以分为多个独立的模块,比如,上一次提高的 hello 函数,如果我们定义为一个模块,其它模块引用之后,直接调用就好了.在前端怎么使用模块呢?这可说来话长 ...
- AngularJS快速入门指南19:示例代码
本文给出的大部分示例都可以直接运行,通过点击运行按钮来查看结果,同时支持在线编辑代码. <div ng-app=""> <p>Name: <input ...
- AngularJS快速入门指南16:Bootstrap
thead>tr>th, table.reference>tbody>tr>th, table.reference>tfoot>tr>th, table ...
- AngularJS快速入门指南15:API
thead>tr>th, table.reference>tbody>tr>th, table.reference>tfoot>tr>th, table ...
- Vue 入门指南 JS
Vue 入门指南 章节导航 英文:http://vuejs.org/guide/index.html 介绍 vue.js 是用来构建web应用接口的一个库 技术上,Vue.js 重点集中在MVVM模式 ...
随机推荐
- Shell 脚本实践
1. 脚本判断命令输出是否为空 (1)判断字符串为空 if [ "$str" = "" ] if [ x"$str" = x ] if ...
- 关于chrom开发者工具priview和respons 数据内容不一致问题
在昨天晚上2017年8月24日,深夜升级的时候发现你了一个问题:简单的把问题描述一下:新增的一个付款单中的金额为最大值9999999999999999 ,但是保存后返回来的却是100000000000 ...
- REALTEK 刷机方法 法
REALTEK 是通用板最多的IC 方案之一,什么常说的2025 2270 2023 2033 2525 2545 2660 2280 2662 2670 2672 2674 2661 2668 ...
- 【Android测试工具】Android抓包解析全过程
需求原因 在android开发中,遇到socket编程,无法从log日志中查看到与之通讯的socket发送和返回的数据包是什么,这里介绍一个工具,tcpdump工具和wireshark工具查看抓到的内 ...
- Mongodb3.0.5副本集搭建及spring和java连接副本集配置
这是去年写的一篇文档,最近突然发现并没有发不出来,因此现在补上,希望能对某些朋友有所帮助.因为当时记录时没有截图,因此这里看起来可能就比较单调. 一.基本环境: mongdb3.0.5数据库 spri ...
- cookie、session和java过滤器
基础知识理解: cookie.session和过滤器通常都是用在web应用中,cookie和session用来保存一定的数据,过滤器Filter则是在浏览器发出请求之后,而后台执行特定的请求之前发生一 ...
- 蜻蜓FM 涉嫌诈骗投资人和广告主源代码剖析
本文主要内容,引用自知乎的这篇文章:如何评价蜻蜓 FM 伪造用户活跃度等数据 感谢"左莫"."任正"等热心正义的网友--左莫,任正的最早的回答猜测已经被蜻蜓FM ...
- windows2003服务器系统日志:查看电脑远程登录记录
控制面板>>管理工具>>事件查看器>>选择安全性再点工具栏目中查看>>筛选>>事件ID填528进行过滤,时间你看是多久,双击查看之后就可以找 ...
- Netty未来展望
作为<Netty权威指南(第2版)>的结尾章节,和读者朋友们一起展望下Netty的未来. 1应用范围 随着大数据.互联网和云计算的发展,传统的垂直架构逐渐将被分布式.弹性伸缩的新架构替代. ...
- Flex和Java通信报错
1.错误描述 11-30 18:15:52 ERROR [localhost-startStop-1] org.springframework.web.servlet.FrameworkServlet ...