Javascript中的类

类是对象的模板,用于创建共享一系列属性和方法的类似对象。

使用new关键字调用函数,可以创建对象实例。

 function Accommodation(){};

 var house = new Accommodation();

 var apartment = new Accommodation();

同一模板的对象实例之间互无关联,这些对象实例是完全独立的变量,只不过共享同一个模板结构而已。

类的扩充:

1.找出对象的构造器

通过new关键字创建的对象的实例,有一个额外的属性:constructor,该属性指向创建该对象时所使用的JavaScript构造函数。

 house.constructor === Accommodation;//true

 apartment.constructor === Accommodation;//true

关键字instanceof也可以检查对象是否是某个构造函数的实例。

house instanceof Accommodation;

apartment instanceof Accommmodation;

2.通过原型添加属性和方法

Javascript中的每个函数(构造器)都有一个叫prototype的属性,这个属性指向一个对象,我们用关键字new来创建一个“类”的对象实例时,实例中包含的属性和方法都来自prototype所指向的这个对象。

//定义构造函数
function Accommodation(){} //为这个类添加属性
Accommodation.prototype.floors = 0;
Accommodation.prototype.rooms = 0;
Accommodation.prototype.sharedEntrance = false; //为这个类添加方法
Accommodation.prototype.lock = function(){};
Accommodation.prototype.unlock = function(){}; //创建对象实例
var house = new Accommodation();
var apartment = new Accommodation(); //读取对象实例的属性
console.log(house.floors);//
console.log(apartment.rooms);// //修改对象属性的值
house.floors = 2;
apartment.sharedEntrance = true; //调用对象实例的方法
house.unlock();
apartment.lock();

prototype属性本身是一个对象,这个对象被关联在扮演“类”这个角色的函数身上,因此,还可以用对象直接量标记法为构造函数添加属性和方法。

//定义构造函数
function Accommodation(){} //为这个类添加属性和方法
Accommodation.prototype = {
floors: 0,
rooms: 0,
sharedEntrance: false,
lock: function(){},
unlock: function(){}
}

prototype这个关键字有一个强大的特性:允许在对象实例已经被创建后继续添加属性和方法,新增属性和方法会自动添加到所有对象实例中,不管是已创建的还是将要创建的。

3.通过作用域添加属性和方法

javascript函数体内定义的变量和函数,作用域都限于函数体内,在该函数体外无法访问这些变量和函数——对这些函数和变量来说,包裹他们的外层函数提供了一个沙箱般的编程环境,或者说一个闭包。

4.上下文和this关键字

javascript中this关键字代表的是一个函数的上下文环境,这个上下文环境大多数情况下指的是函数运行时封装这个函数的那个对象。

//在所有函数之外,this表示的是全局window对象
console.log(this === window);//true //因为doSomething函数在对象外部被调用,this指向的是浏览器中的window对象
function doSomething(){
console.log(this === window); //true
} doSomething(); var house = {
floors: 2,
isLocked = false,
lock: function(){
console.log(this === house);//true 因为this关键字代表的是包含这个方法的那个对象
//也可以把this看做house对象的替身,可以使用点标记法
this.isLocked = true;
},
} house.lock();
console.log(house.isLocked);//true

对象中的嵌套函数其上下文环境是全局的window对象,而非包含它的那个对象。但我们可以在this指向包含这个函数的对象时,将this的值保存在一个变量中,在用到该对象时用这个变量代替。

var apartment = {
islocked: false,
lock: function(){
var that = this;
//设置isLocked属性
this.isLocked = true;
function doSomething(){
console.log(this === apartment);//false
console.log(this === window);//false
console.log(that === apartment);//false
//通过that变量来修改apartment对象的isLocked属性
that.isLocked = false;
}
doSomething();
},
} apartment.lock(); console.log(apartment.isLocked);//false

在使用new关键字创建对象时,this指向的值和一般情况下又有区别,这种情况下this指向的是通过构造函数所创建的那个对象实例。也因为这个特性,得以在构造函数中通过this来设置所有对象实例的属性和方法,而非像之前那样使用prototype关键字。

//定义一个新的构造函数来表示一种住宅
function Accommodation(){
//this关键字指向的是通过这个“类”创建的对象实例
this.floors = 0;
this.rooms = 0;
this.sharedEntrance = false;
this.isLocked = false;
this.lock = function(){
//函数中的this一般指向包含函数的那个对象,本例中的this指向的是创建的对象实例,因为这个函数是通过这个被创建的对象实例来调用的
this.isLocked = true;
};
this.unlock = function(){
this.isLocked = false;
}
} //通过构造函数来创建对象实例
var house = new Accommodation();
var apartment = new Accommodation(); //读取和修改属性值,调用方法等操作都和普通对象一样
console.log(house.floors);
house.floors = 2;
apartment.lock();

开发者一般会结合使用prototype和this关键字来定义对象实例的属性和方法,其中前者用来定义方法,后者用来定义属性。每次通过构造器创建一个新的对象实例,构造函数都会被执行一次。之所以结合使用这两个关键字,是为了避免每次初始化一个对象实例时都要执行那些对方法进行初始化的代码。通过prototype关键字定义的方法只需定义一次,然后就可以为所有通过这个构造函数创建的对象所用,这使得对象的创建变得更加高效;

开发者们喜欢在构造函数中使用this关键字来设置属性的另一个原因是可以给构造函数传递参数,这样我们就能在调用构造函数时通过传递参数来对某些属性进行初始化了。

我们也可以向构造函数传递一个对象直接量作为唯一的参数,这个对象直接量包含了进行属性设置所需的所有初始值。

5.方法的链式调用

要实现链式调用,只需在“类”中的每个方法最后通过this关键字返回对象实例的引用即可。

6.继承

传统编程语言的一项关键功能就是可以创建一些新的类来继承或者扩展某个父类的属性和方法,这些新的类和该父类都有某种类似的逻辑关联,这些新的类被称为子类。

Javascript中也可以实现这种继承,不过是通过Javascript的原型链来实现,被称为原型继承。

//定义一个有两个方法的类
function Accommodation(){} Accommodation.prototype.lock = function(){}
Accommodation.prototype.unlock = function(){} //定义一个构造函数,它将成为我们的子类
function House(defaults) {
defaults = defaults || {};
//将本类所有实例的floors属性初始化为2
this.floors = 2; this.rooms = defaults.rooms ||7;
} //将House类的原型设为Accommodation“类”的一个实例,使用关键字new来调用Accommodation的构造函数,这样就能创建并返回一个包含所有属性和方法的对象。这个对象被传递给House"类"的原型,这样House"类"就得以继承Accommodation 的所有内容
House.prototype = new Accommodation(); //对象实例的constructor属性指向创建该对象的那个构造函数,然而由于House继承了Accommodation的所有内容,constructor值也被复制了,所以我们现在需要重设constructor值,使其指向新的子类。如果没有这一步,通过House"类"创建的对象就会报告说他们是通过Accommodation“类”创建的。
House.prototype.constructor = House;

封装:

当通过继承对已有的类进行改变或特殊化时,父类的所有属性和方法对子类都是可用的,在子类中不需要额外声明或定义任何东西就能使用父类的属性和方法,这种特性被称为封装。子类之需要定义那些在父类基础上新增的属性和方法即可;

多态:

在构造一个新的子类来继承并扩展一个“类”的时候,你可能需要将某个方法替换为一个同名的新方法,新方法和原方法功能类似,但对子类做出了针对性的改变,这就是多态,Javascript中实现多态,只需重写一个函数并给它一个和原方法形同的方法即可;

call和apply

arguments对象

公有,私有以及受保护的属性和方法

在构造函数中通过var定义的变量其作用域局限于该构造函数内——在prototype上定义的方法无法访问这个变量,因为这些方法有自己的作用域。要想通过公有的方法来访问私有的变量,需要创建一个同时包含两个作用域的新作用域,为此,我们可以创建一个自我执行的函数,称为闭包。该函数完全包含了类的定义,包括所有私有变量以及原型方法。

javascript有一个非强制性的但很有用的编程惯例,就是对所有私有变量或函数名加一个下划线(_)作为前缀,以标识他们是私有的,这有助于你及项目组的其他成员更好的理解每个类的作者的意图。

// 我们将类定义包在一个自我执行的函数里,这个函数返回我们所创建的类并将其保存在一个变量中,一边在后面的代码中使用
var Accommodation = (function(){
//定义类的构造函数,因为处于一个新的函数内,我们也切换到了一个新的作用域中,所以可以使用与保存函数返回值得那个变量相同的名字
function Accommodation(){
//此处定义的变量都是私有的,这些变量在当前作用域之外不可用,可以通过变量名添加下划线前缀来标识这一点
var _isLocked = false,
_isAlarmed = false,
_alarmMessage = "Alarm activated!";
//仅在当前作用域中定义的函数(未在构造函数上定义的)也是私有的
function _alarm(){
_isAlarmed = true;
alert(_alarmMessage);
} function _disableAlarm(){
_isAlarmed = false;
} //所有定义在原型上的方法都是公有的,当我们在此处创建爱你的类在闭包结束处被返回后,就可以在当前作用域之外访问这些方法了
Accommodation.prototype.lock =function(){
_isLocked = true;
_alarm();
} Accommodation.prototype.unlock = function(){
_isLocked = false;
_disableAlarm();
} //定义一个getter函数来对私有变量_islocked的值进行只读访问——相当于把该变量定义为了受保护的
Accommodation.prototype.getIsLocked = function(){
return _isLocked;
} //定义一个setter函数来对私有变量_alarmMessage进行只写访问——相当于将其定义为了受保护的
Accommodation.prototype.setAlarmMessage = function(message){
_alarmMessage = message;
} //返回在这个作用域中创建的类,使之在外层作用域中即后面的代码中的所有位置都可用,只有公有的属性和方法是可用的
return Accommodation;
}
}());

面向对象的JavaScript-小结的更多相关文章

  1. 前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型

    前端开发:面向对象与javascript中的面向对象实现(二)构造函数与原型 前言(题外话): 有人说拖延症是一个绝症,哎呀治不好了.先不说这是一个每个人都多多少少会有的,也不管它究竟对生活有多么大的 ...

  2. 前端开发:面向对象与javascript中的面向对象实现(一)

    前端开发:面向对象与javascript中的面向对象实现(一) 前言: 人生在世,这找不到对象是万万不行的.咱们生活中,找不到对象要挨骂,代码里也一样.朋友问我说:“嘿,在干嘛呢......”,我:“ ...

  3. 面向对象的 JavaScript

    面向对象的javascript 一.创建对象 创建对象的几种方式: var obj = {}; var obj = new Object(); var obj = Object.create(fath ...

  4. 摘抄--全面理解面向对象的 JavaScript

    全面理解面向对象的 JavaScript JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或 ...

  5. 面向对象的JavaScript --- 动态类型语言

    面向对象的JavaScript --- 动态类型语言 动态类型语言与面向接口编程 JavaScript 没有提供传统面向对象语言中的类式继承,而是通过原型委托的方式来实现对象与对象之间的继承. Jav ...

  6. 面向对象的JavaScript --- 封装

    面向对象的JavaScript --- 封装 封装 封装的目的是将信息隐藏.一般而言,我们讨论的封装是封装数据和封装实现.真正的封装为更广义的封装,不仅包括封装数据和封装实现,还包括封装类型和封装变化 ...

  7. 面向对象的JavaScript --- 多态

    面向对象的JavaScript --- 多态 多态 "多态"一词源于希腊文 polymorphism,拆开来看是poly(复数)+ morph(形态)+ism,从字面上我们可以理解 ...

  8. 面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统

    面向对象的JavaScript --- 原型模式和基于原型继承的JavaScript对象系统 原型模式和基于原型继承的JavaScript对象系统 在 Brendan Eich 为 JavaScrip ...

  9. 第1章 面向对象的JavaScript

    针对基础知识的每一个小点,我都写了一些小例子,https://github.com/huyanluanyu1989/DesignPatterns.git,便于大家理解,如有疑问,大家可留言给我,最近工 ...

  10. javascript面向对象之Javascript 继承

    转自原文javascript面向对象之Javascript 继承 在JavaScript中实现继承可以有多种方法,下面说两种常见的. 一,call 继承 先定义一个“人”类 //人类 Person=f ...

随机推荐

  1. oracle分析性能问题实例

    摘录于SAP有关分析ORACLE数据性能事件的文档. 1.A check for the distribution of relevant Oracle server time revealed: 有 ...

  2. Angular2+URL中的 # 引发的思考

    1.先分析 # 的作用 1.1. # 的涵义 #代表网页中的位置.其右面的字符就是该位置的标识符.比如,http://www.example.com/index.html#print就代表网页inde ...

  3. Java 自增原理

    很多人都知道 i++ 和 ++i 的区别 a = i++: a = i; i = i+1; a = ++ i; i = i + 1; a = i; 但碰到 i = i ++;的时候很多人就懵了? i是 ...

  4. js简单封装样式

    class Foo{ constructor(name) { this.name = name } greet() { console.log('hello this is',this.name) } ...

  5. PHP 轻量级 REST框架

    GITHUB:https://github.com/jacwright/RestServer 简介: 一个PHP REST服务器,用于提供非常轻量级的REST API.很容易上手.独立于其他库和框架. ...

  6. python之路-python2.x与python3.x区别

    Python崇尚优美.清晰.简单,是一个优秀并广泛使用的语言. Python2.x 与 Python3.x的区别: python2.x:源码混乱,重复代码较多,冗余. python3.x:源码规范,崇 ...

  7. Angular No name was provided for external module 'XXX' in output.globals 错误

    Angular 7 开发自定义库时,引用ngZorroAntd,build过程中出现 No name was provided for external module 'ng-zorro-antd' ...

  8. Android : Camera之CHI API

    一.CAM CHI API功能介绍: CHI API建立在Google HAL3的灵活性基础之上,目的是将Camera2/HAL3接口分离出来用于使用相机功能,它是一个灵活的图像处理驱动程序(摄像头硬 ...

  9. java基础2(二)

    Servlet 注意: servletConfig可以获取配置文件(xml文件)中配置的servlet对象的初始化参数. url-pattern 缺省servlet 注意:tomcat目录下有一个默认 ...

  10. windows环境下,spring boot服务使用docker打包成镜像并推送到云服务器私有仓库

    最近在淘宝上学习springcloud教程,其中有几节课是讲解讲本地springboot服务打包成镜像并推送到云服务器私有仓库,但是教程里面用的事Mac环境,我的是Windows环境,而且课程里面没有 ...