晴明的博客园 GitHub      CodePen      CodeWars     

[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());
posted @ 2017-03-20 10:40  晴明桑  阅读(227)  评论(0编辑  收藏  举报