[js] 面向对象
Object.defineProperty的使用
var Cat = (function () {
let count = 0;
let sum = 0;
function o(name, weight) {
if (!name || !weight) {
throw 'error';
}
let w = weight;
sum += w;
count++;
Object.defineProperty(this, 'weight', {
get: function () {
return w;
},
set: function (value) {
//不知道这个set如何触发
sum += value - w;
w = value;
}
})
}
o.averageWeight = function () {
return sum / count;
}
return o;
}());
fluffy = new Cat('fluffy', 15);
garfield = new Cat('garfield', 25);
Test.assertEqual(fluffy.weight, 15);
Test.assertEqual(fluffy instanceof Cat, true);
Test.assertEqual(fluffy.averageWeight, undefined);
Test.assertEqual(typeof Cat.averageWeight, "function");
Test.assertEqual(Cat.averageWeight(), 20);
观察者模式
//ES5实现
function Event() {
this.handlers = [];
this.subscribe = function (func) {
this.handlers.indexOf(handler) === -1 && this.handlers.push(func);
};
this.unsubscribe = function (func) {
this.handlers.splice(this.handlers.indexOf(func), 1);
};
this.emit = function () {
let targuments = arguments;
let that = this;
this.handlers.forEach(function (func) {
func.apply(that, targuments);
});
};
}
//ES6实现
class Event {
constructor() {
this.handlers = new Set();
}
subscribe(f) {
this.handlers.add(f);
}
unsubscribe(f) {
this.handlers.delete(f);
}
emit(...args) {
this.handlers.forEach( f => f(...args) );
//this.handlers.forEach((f) => f.apply(this, arguments));
}
}
var event = new Event();
function f() {
f.calls = (f.calls || 0) + 1;
f.args = Array.prototype.slice.call(arguments);
}
event.subscribe(f);
event.emit(1, 'foo', true);
Test.expect(f.calls === 1); // calls a handler
Test.assertSimilar(f.args, [1, 'foo', true]); // passes arguments
event.unsubscribe(f);
event.emit(2);
Test.expect(f.calls === 1); //no second call
杂
过去的一些写法
// let Test = function () {
// function inner() {
// return 'innner';
// }
// // let inner = function () {
// // return 'innner';
// // }//一样的
// inner.hello = function () {
// return 'hello';
// }
// inner.bye = function () {
// return 'bye';
// }
// return inner;
// }//一样的
function Test() {
function inner() {
return 'innner';
}
// let inner = function () {
// return 'innner';
// }//一样的
inner.hello = function () {
return 'hello';
}
inner.bye = function () {
return 'bye';
}
return inner;
}
let Try = Test();
console.log(Try)//function inner
console.log(Try.hello())//hello
console.log(Try.bye())//bye
function Test() { }
Test.hello = function () {
return 'hello';
}
Test.bye = function () {
return 'bye';
}
console.log(Test.hello())//hello
console.log(Test.bye())//bye
let Test = {
hello: function () {
return 'hello';
},
bye: function () {
return 'bye';
}
}
console.log(Test.hello())//hello
console.log(Test.bye())//bye
现在的一些写法
class Test {
constructor(x) {
this.x = x;
}
name() {
return 'xx'
}
hello() {
return `hello ${this.name()}`;
}
bye() {
return `bye ${this.x}`;
}
}
let Try = new Test('robin');
console.log(Try)//Test {x: "robin"}
console.log(Try.hello())//hello xx
console.log(Try.bye())//bye robin
//立即执行
let person = new class {
constructor(name) {
this.name = name;
}
sayName() {
console.log(this.name);
}
}('张三');
person.sayName(); // "张三"
class Test {
static hello() {
return 'hello';
}
static bye() {
return 'bye';
}
}
console.log(Test.hello())//hello
console.log(Test.bye())//bye
实现私有方法
foo是公有方法,内部调用了bar.call(this, baz)。
这使得bar实际上成为了当前模块的私有方法。
class Widget {
foo (baz) {
bar.call(this, baz);
}
// ...
}
function bar(baz) {
return this.snaf = baz;
}
另一种方法是利用Symbol值的唯一性,将私有方法的名字命名为一个Symbol值。
bar和snaf都是Symbol值,导致第三方无法获取到它们,因此达到了私有方法和私有属性的效果。
const bar = Symbol('bar');
const snaf = Symbol('snaf');
export default class myClass{
// 公有方法
foo(baz) {
this[bar](baz);
}
// 私有方法
[bar](baz) {
return this[snaf] = baz;
}
// ...
};
class中this指向的问题
printName方法中的this,默认指向Logger类的实例。
但是,如果将这个方法提取出来单独使用,this会指向该方法运行时所在的环境,因为找不到print方法而导致报错。
class Logger {
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // TypeError: Cannot read property 'print' of undefined
在构造方法中绑定this
class Logger {
constructor() {
this.printName = this.printName.bind(this);
}
printName(name = 'there') {
this.print(`Hello ${name}`);
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // Hello there
在构造方法中使用箭头函数
class Logger {
constructor() {
this.printName = (name = 'there') => {
this.print(`Hello ${name}`);
};
}
print(text) {
console.log(text);
}
}
const logger = new Logger();
const { printName } = logger;
printName(); // Hello there
使用Proxy,获取方法的时候,自动绑定this。
function selfish (target) {
const cache = new WeakMap();
const handler = {
get (target, key) {
const value = Reflect.get(target, key);
if (typeof value !== 'function') {
return value;
}
if (!cache.has(value)) {
cache.set(value, value.bind(target));
}
return cache.get(value);
}
};
const proxy = new Proxy(target, handler);
return proxy;
}
const logger = selfish(new Logger());