本日整顿面试题的时刻瞥见一道题叫讲一下继续,虽然继续之前也看过书,也在用,然则竟然没法总结性、体系地回复这个题目,因而赶忙把《JavaScript设想形式》扒拉出来看看。
为何须要继续
在设想类的时刻,能够削减重复性代码,并且能只管弱化对象间的耦合。能够在现有类的基础上举行设想并充分利用已具有的种种要领,而对设想的修正也更加轻松。
继续一共有三种体式格局:类式继续、原型式继续、掺元类
类式继续
JavaScript能够被装扮成运用类式继续的言语。经由历程用函数来声明类、用关键字 new 来建立实例,JavaScript中的对象也能模拟Java或C++中的对象。
起首制造一个简朴的类声明,及对该类的实例化:
// 建立 Person 类
function Person (name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
};
// 实例化 Person 类
var reader = new Person ('John Smith');
reader.getName(); // John Smith
建立继续 Person 的类 Author :
// 建立继续 Person 的类 Author
function Author (name,books) {
Person.call(this,name);
this.book = books;
}
// 派生子类
Author.prototype = new Person();
Author.prototype.constructor = Author;
Author.prootype.getBooks = function () {
return this.book;
};
在默许状况下,统统原型对象都邑自动取得一个 constructor (组织函数)属性,这个属性是一个指向 prototype 属性地点函数的指针。
为了简化类的声明。能够把派生子类的全部历程包装在一个名为 extend 的函数中,作用是基于一个给定的类构造建立一个新的类。
// extend 函数
function extend(subClass,superClass) {
var F = function() {};
F.prototype = superClass.prototype;
subClass.prototype = new F();
subClass.prototype.constructor = subClass;
// 确保超类的 constructor 属性被设置准确
subClass.superclass = superClass.prototype;
if(superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass;
}
}
那末 Author 的继续能够改写为:
function Author (name,books) {
Author.superClass.contructor.call(this,name);
this.books = books;
}
extend(Author,Person); // 挪用 extend 函数
Author.prootype.getBooks = function () {
return this.book;
};
原型式继续
原型式继续和类式继续判然不同。在进修原型式继续时,最好忘记本身关于类和实例的统统学问,只从对象的角度来斟酌。
在运用原型式继续时,不须要用类来定义对象的构造,只需直接建立一个对象即可。这个对象随后能够被新的对象重用,这得益于原型链查找的事情机制,该对象被称为原型对象。
下面运用原型式继续来从新设想 Person 和 Author
// Person 原型对象
var Person = {
name: 'default name',
getName: function() {
return this.name;
}
};
Person 现在是一个对象字面量,个中定义了统统类 Person 对象都要具有的属性和要领,并为他们供应了默许值。clone 函数能够用来建立新的类 Person 对象,该函数会建立一个空对象,而该对象的原型对象被设置为 Person。
// Author 原型对象
var Author = clone(Person);
Author.books = []; // Default value
Author.getBooks = function () {
return this.books;
};
一个克隆并不是原型对象的一份完整自力的副本,它只是一个以谁人对象为原型对象的空对象。对继续而来的成员有读和写的不对等性:
var authorClone = clone(Author);
alert(authorClone.name); // default name (连接到 Person.name)
authorClone.name = 'new name';
alert(authorClone.name); // new name (连接到 authorClone.name)
authorClone.books.push('new book'); // 在这里,想authorClone.books数组增加
// 新元素实际上是把这个元素增加到
// Author.books数组中。
authorClone.books = [];
authorClone.books.push('new book');
这也就说清楚明了为何必需为经由历程援用通报的数据类型的属性建立新的副本。在以上例子中,向authorClone.books数组增加新元素实际上是把这个元素增加到Author.books数组中。这可不是什么功德,由于对谁人值的修正不仅会影响到 Author,而且会影响到统统机场了Author但还未改写谁人属性的默许值的对象。在转变统统那些数组和对象的成员之前,必需先为其建立新的副本。
相似继续和原型式继续的对照
包含JavaScript程序员在内的全部程序员群体对类式继续都比较熟习。
原型式继续更能勤俭内存。在原型链中查找成员的体式格局使得统统克隆出来的对象都同享每一个属性和唯一一份实例,只要在直接设置了某个克隆出来的对象的属性和要领时,状况才会有所变化。而相似继续体式格局中建立的每一个对象在内存中都有本身的一套属性的副本。