类和模块
1. 类和原型
- 利用工厂函数创建范围类初始化实例:
function range(from, to){
var r = Object.create(range.methods);
r.from = from;
r.to = to;
return r;
}
//左闭右开
range.methods = {
includes: function(x){
return x >= this.from && x < this.to;
},
foreach: function(f){
for(var x = Math.ceil(this.from); X < this.to; x++)
f(x);
},
toString: function(){
return "(" + this.from + "..." + this.to + ")";
}
};
var r = range(1, 3); // => 返回一个对象
r.includes(2); // => true
r.foreach(console.log); // => 1, 2
console.log(r); // => (1...3)
2. 类和构造函数
- 利用构造函数定义范围类:
function Range(from, to){
this.from = from;
this.to = to;
}
//左闭右开
Range.prototype = {
includes: function(x){
return x >= this.from && x < this.to;
},
foreach: function(f){
for(var x = Math.ceil(this.from); X < this.to; x++)
f(x);
},
toString: function(){
return "(" + this.from + "..." + this.to + ")";
}
};
var r = new Range(1, 3); // => 返回一个对象
r.includes(2); // => true
r.foreach(console.log); // => 1, 2
console.log(r); // => (1...3)
类的标识:
如上:r instanceof Range // 如果r继承自Range.prototype则返回true
instanceof 不会检查r是否由Range()构造函数初始化,而是检查其proto是否是Range.prototype(即是否继承自Range.prototype)constructor:
每个js函数拥有一个prototype属性,该属性值是一个对象,对象中包含一个不可枚举属性constructor,该属性的值是一个函数对象,即该函数本身的定义:
var F = function(){};
var p = F.prototype;
var cons = p.constructor;
cons === F; // => true
构造函数 原型 实例
|Range() |<-----| 构造函数| 继承
| | | includes| <-------- new Range(1, 2)
| 原型 |----->| foreach |
由于我们显示定义了Range的prototype,因此应该显示指定constructor:
Range.prototype = {
constructor: Range,
includes: function(x){
return x >= this.from && x < this.to;
},
foreach: function(f){
for(var x = Math.ceil(this.from); X < this.to; x++)
f(x);
},
toString: function(){
return "(" + this.from + "..." + this.to + ")";
}
};
3. prototype与proto:
- 几乎所有的函数(除了一些内建函数)都有一个名为prototype(原型)的属性,这个属性是一个指针,指向一个对象,而这个对象的用途是包含可以有特定类型的所有实例共享的属性和方法。prototype是通过调用构造函数而创建的那个对象实例的原型对象。hasOwnProperty()判断指定属性是否为自有属性;in操作符对原型属性和自有属性都返回true。
var obj = {a: 1};
obj.hasOwnProperty("a"); // true
obj.hasOwnProperty("toString"); // false
"a" in obj; // true
"toString" in obj; // true
- 对象具有属性proto,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
function Foo(){}
var Boo = {name: "Boo"};
Foo.prototype = Boo;
var f = new Foo();
console.log(f.__proto__ === Foo.prototype); // true
console.log(f.__proto__ === Boo); // true
Object.getPrototypeOf(f) === f.__proto__; // true
即一个由new获取的对象, 其proto隐藏属性的值, 是其构造函数的prototype属性值对应的对象。
4. 定义子类:
- 方法:例如定义A的子类B
B.prototype = Object.create(A.prototype);
B.prototype.constructor = B
- 一个巧妙的方式定义工厂函数+构造函数
function Range(from, to){
var prop = {
from: {value: from, enumerable: true, writable: false, configurable: false},
to: {value: to, enumerable: true, writable: false, configurable: false}
};
if (this instanceof Range) //判断是否为构造函数调用
Object.defineProperties(this, prop);
else //函数调用
return Object.create(Range.prototype, prop);
}