Javascript中的类javascript
类是对象的模板,用于建立共享一系列属性和方法的相似对象。java
使用new关键字调用函数,能够建立对象实例。编程
1 function Accommodation(){}; 2 3 var house = new Accommodation(); 4 5 var apartment = new Accommodation();
同一模板的对象实例之间互无关联,这些对象实例是彻底独立的变量,只不过共享同一个模板结构而已。浏览器
类的扩充:闭包
1.找出对象的构造器app
经过new关键字建立的对象的实例,有一个额外的属性:constructor,该属性指向建立该对象时所使用的JavaScript构造函数。编程语言
1 house.constructor === Accommodation;//true 2 3 apartment.constructor === Accommodation;//true
关键字instanceof也能够检查对象是不是某个构造函数的实例。函数
house instanceof Accommodation; apartment instanceof Accommmodation;
2.经过原型添加属性和方法this
Javascript中的每一个函数(构造器)都有一个叫prototype的属性,这个属性指向一个对象,咱们用关键字new来建立一个“类”的对象实例时,实例中包含的属性和方法都来自prototype所指向的这个对象。spa
//定义构造函数 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);//0 console.log(apartment.rooms);//0 //修改对象属性的值 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; } }());