sailei1 / blog

1 stars 0 forks source link

你不知道的JS - 行为委托 笔记 #74

Closed sailei1 closed 4 years ago

sailei1 commented 4 years ago

在 JavaScript 中,[[Prototype]] 机制会把对象关联到其他对象。无论你多么努力地说服自己,JavaScript 中就是没有类似“类”的抽象机制。 委托最好在内部实现,不要直接暴露出去

两个或两个以上互相(双向)委托的对象之间创建循环委托。如果你把 B 关联到A 然后试着把 A 关联到 B,就会出错。 当你使用对象关联风格来编写代码并使用行为委托设计模式时,并不需要关注是谁“构造了”对象(就是使用 new 调用的那个函数)。 JavaScript 中 的 函 数 之 所 以 可 以 访 问 call(..)、apply(..) 和 bind(..),就是因为函数本身是对象。而函数对象同样有 [[Prototype]] 属性并且关联到 Function.prototype 对象,因此所有函数对象都可以通过委托调用这些默认方法。

“类”和“委托”这两种设计模式的理论区别

function Foo(who) { 
  this.me = who;
}
Foo.prototype.identify = function() {
   return "I am " + this.me; 
};
function Bar(who) { 
    Foo.call( this, who );
}
Bar.prototype = Object.create( Foo.prototype );
Bar.prototype.speak = function() {
   alert( "Hello, " + this.identify() + "." );
};
var b1 = new Bar( "b1" );
var b2 = new Bar( "b2" ); 
b1.speak();
b2.speak();
屏幕快照 2019-10-22 16 16 35
Foo = {
init: function(who) {
    this.me = who; 
    },
identify: function() {
   return "I am " + this.me;
} 
};
Bar = Object.create( Foo );
Bar.speak = function() {
  alert( "Hello, " + this.identify() + "." );
};
var b1 = Object.create( Bar );
b1.init( "b1" );
var b2 = Object.create( Bar );
b2.init( "b2" );
b1.speak();
b2.speak();
屏幕快照 2019-10-22 16 19 11

es6 class 尽管语法上得到了改进,但实际上这里并没有真正的类,class 仍然是通过 [[Prototype]]机制实现的。 es6 class 优点 1.不再引用杂乱的 .prototype 2.不再需要通过Object.create(..)来替换 .prototype 对象,也不需要设置 .proto 或者 Object.setPrototypeOf(..)。 3.可以通过super(..)来实现相对多态,这样任何方法都可以引用原型链上层的同名方法。

  1. class 字面语法不能声明属性(只能声明方法)
  2. 可以通过extends很自然地扩展对象(子)类型,甚至是内置的对象(子)类型,比如Array 或 RegExp 缺点:
    class C { 
    constructor() {
    // 确保修改的是共享状态而不是在实例上创建一个屏蔽属性!
    C.prototype.count++;
    // this.count 可以通过委托实现我们想要的功能
    console.log( "Hello: " + this.count );
     }
    }
    // 直接向 prototype 对象上添加一个共享状态
    C.prototype.count = 0;
    var c1 = new C(); // Hello: 1
    var c2 = new C(); // Hello: 2
    c1.count === 2; // true
    c1.count === c2.count; // true
    //它违背了 class 语法的本意,在实现中暴露(泄露!)了 .prototype。