Prototypes
You can use
Object.create()to create an object with a specific prototype.
let protoRabbit = {
speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
},
};
console.log(typeof protoRabbit); // -> object
let killerRabbit = Object.create(protoRabbit);
killerRabbit.type = 'killer';
console.log(Object.keys(killerRabbit)); // -> ["type"]
console.log(Object.getPrototypeOf(killerRabbit));
console.log(protoRabbit.isPrototypeOf(killerRabbit)); // -> true
killerRabbit.speak('SKREEEE!');
- The "proto" rabbit acts as a container for the properties that are shared by all rabbits.
- An individual rabbit object, like the killer rabbit, contains properties that apply only to itself and derives shared properties from its prototype.
Object.keys()输出的properties不包含对象从原型那里继承来的,所以console.log(Object.keys(killerRabbit))输出的结果是["type"]。
另外,上面涉及到Object.create()这个知识点。
The
Object.create()method creates a new object, using an existing object as the prototype of the newly created object.
- Object.create()的参数是一个object
- 新创建的对象的prototype是Object.create()的参数 所以,上面代码里面,console.log(Object.getPrototypeOf(killerRabbit))输出的答案是:
也就是说,killerRabbit的prototype是protoRabbit这个object。
Classes
So JavaScript classes are constructor functions with a prototype property. 这个定义很重要。
2015年之前,class的写法就是直接声明一个constructor function,大概像下面这样子:
function Rabbit(type) {
this.type = type;
}
Rabbit.prototype.speak = function (line) {
console.log(`The ${this.type} rabbit says '${line}'`);
};
let weirdRabbit = new Rabbit('weird');
2015年之后,可以用Class Notation来写:
class Rabbit {
constructor(type) {
this.type = type;
}
speak(line) {
console.log(`The ${this.type} rabbit says '${line}'`);
}
}
let killerRabbit = new Rabbit("killer");
let blackRabbit = new Rabbit("black");
The Iterator Interface
The object given to a
for / ofloop is expected to be iterable. 具体实例:搭建一个matrix类别
class Matrix {
// 初始化,创建一个matrix[width][height]
constructor(width, height, element = (x, y) => undefined) {
this.width = width;
this.height = height;
this.content = []; // single array representation of a two-dimensional array
for (let y = 0; y < height; y++) {
for (let x = 0; x < width; x++) {
this.content[y * width + x] = element(x, y);
}
}
}
get(x, y) {
return this.content[y * this.width + x];
}
set(x, y, value) {
this.content[y * this.width + x] = value;
}
}
第二步:创建一个MatrixIterator class
class MatrixIterator {
constructor(matrix) {
this.x = 0;
this.y = 0;
this.matrix = matrix;
}
// 注意next()的写法
next() {
if (this.y == this.matrix.height) return { done: true };
let value = {
x: this.x,
y: this.y,
value: this.matrix.get(this.x, this.y),
};
this.x++;
if (this.x == this.matrix.width) {
this.x = 0;
this.y++;
}
return { value, done: false };
}
}
第三步:给Matrix.prototype加一个Symbol.iterator方法
Matrix.prototype[Symbol.iterator] = function () {
return new MatrixIterator(this); // 返回的是一个MatrixIterator的object
};
第四步:创建一个Matrix类对象
let matrix = new Matrix(2, 2, (x, y) => `value ${x}, ${y}`);
console.log('constructor' in matrix); // -> true
console.log('get' in matrix); // -> true
console.log('set' in matrix); // -> true
console.log(Symbol.iterator in matrix); // -> true
可以看到,上面代码里面后面四行代码的输出都是true,也就是说matrix这个对象从它的原型那里继承了constructor\get\set\Symbol.iterator。另外,
console.log(Object.keys(matrix));
上面代码输出的结果是:["width", "height", "content"]
第五步:对matrix对象使用for / of
for (let { x, y, value } of matrix) {
console.log(x, y, value);
}
因为matrix是iterable,所以for / of就能顺利输出结果:
0 0 "value 0, 0"
1 0 "value 1, 0"
0 1 "value 0, 1"
1 1 "value 1, 1"