类风格:
// 父类
function Widget(width, height) {this.width = width || 50;this.height = height || 50;this.$elem = null;
}
Widget.prototype.render = function($where) {if(this.$elem) {this.$elem.css({width: this.width + "px",height: this.height + "px"}).appendTo($where);}
};// 子类
function Button(width, height, label) {// 调用父类(Widget)的构造函数Widget.call(this, width, height);this.label = label || "Default";this.$elem = $("<button>").text(this.label);
}// 让Button"继承"Widget(Button可以使用Widget原型上的方法,本例中是render方法)
Button.prototype = Object.create(Widget.prototype);// 重写render
Button.prototype.render = function($where) {// 调用父类(Widget)的render方法Widget.prototype.render.call(this, $where); this.$elem.click(this.onClick.bind(this)); // 监听点击事件
};Button.prototype.onClick = function(evt) {console.log("Button '" + this.label + " 'clicked!" );
};$(document).ready(function() {var $body = $(document.body);var btn1 = new Button(125, 30, "Hello" );var btn2 = new Button(150, 40, "World");btn1.render($body);btn2.render($body);
});// 注:用到了jquery故需要导入cdn <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.js"></script>
上述代码,首先定义了一个Widget的父类,然后使用使用在constructor中使用call方法(作用域绑定到当前)调用父类Widget的初始化…并添加了一个新的$elem(即Butoon标签).
在Button的原型上,使用Object.create()方法继承父类的原型方法(render).并新增了一个(按钮特有的)点击功能.
说明:上面是一个仿照类实现的方法,其实就是使用Widget.call 和Widget.prototype.render.call在Button函数中调用Widget…
用书上的原话说就是…丑陋的显示多态
ES6的class语法糖实现:
class Widget{constructor(width, height) {this.width = width || 50;this.heigth = height || 50;this.$elem = null;}// 很巧妙的render...render($where) {if(this.$elem) {this.$elem.css({width: this.width + "px",height: this.height + "px"}).appendTo($where);}}
}
class Button extends Widget{constructor(width, height, label) {super( width, height);this.label = label || "Default";this.$elem = $("<button>").text(this.label); // 生成一个<button> 内容是label}render($where) { // $where 是调用时传入的参数super.render($where); // 调用父类Widget的renderthis.$elem.click(this.onClick.bind(this));}onClick(evt) {console.log("Button ' " + this.label + " ' clicked!");}
}
$(document).ready(function(){var $body = $(document.body);var btn1 = new Button(125, 30, "Hello" );var btn2 = new Button(150, 40, "World" );btn1.render($body);btn2.render($body);})
//说明: 关键是super替代了伪类中的call方法...变得更简洁(at least看上去是这样...)
委托控件对象:
var Widget = {init: function(width, height){this.width =width || 50;this.height = height || 50;this.$elem = null;},insert: function($where) {if(this.$elem){this.$elem.css({width: this.width + "px",height: this.heigth + "px"}).appenTo($where);}}
};
// 还是定义一个Widget对象,, 使用委托(Object.create)顺着原型链[[prototype]]由下而上读取方法
var Button = Object.create(Widget);Button.setup = function(width, height, label) {this.init(width, height); // Button无init方法,顺着原型链找到了Widget中的init.this.label = label || "Default";this.$elem = $('<button>').text(this.label);
};
Button.build = function($where) {this.insert($where);this.$elem.click(this.onClick.bind(this)); // this.onClick实际上是Button.onClick
};
Button.onClick = function(evt) {console.log("Button '" + this.label + "' clicked!" );
};
$(document).ready(function(){var $body = $(document.body);var btn1 = Object.create(Button);btn1.setup(123, 30, 'Hello');var btn2 = Object.create(Button);btn2.setup(150, 40, 'World');btn1.build($body);btn2.build($body);
});
// 很美的方式
参考《你不知道的JavaScript》(上卷) P174 ~P177