写出 构造函数模式、混合模式、模块模式、工厂模式、单例模式、发布订阅模式的范例。
//单例模式
var Singleton = (function () {
function Singleton(args) {
var args = args || {};
this.name = 'Singleton';
this.pointX = args.pointX || 1;
this.pointY = args.pointY || 2;
}
//实例容器
var instance;
var _static = {
name: '用来玩的默认属性',
/*
* 获取实例的方法
* 返回Singleton的实例
*/
getInstance: function (args) {
if (instance === undefined) {
instance = new Singleton(args)
}
return instance
}
}
return _static
})();
var singletonTest = Singleton.getInstance({ pointX: 5 });
var singletonTest2 = Singleton.getInstance({ pointX: 100000 });
console.log(singletonTest.pointX); // 输出 5
console.log(singletonTest.name); // 输出 "用来玩的默认属性"
console.log(singletonTest2.pointX); // 输出 5
显然单例模式是不适合重复使用的😁
//发布订阅的写法精髓
var EventCenter = (function () {
//这个events会在页面一开始的时候,就注入EventCenter.on所产生的对象
var events = {};
function fire(evt, args) {
if (!events[evt]) {
return;
}
for (var i = 0; i < events[evt].length; i++) {
events[evt][i].handler(args);
//优化的写法,可以调用多个参数
events[evt][i].handler([].slice.call(arguments,1));
}
}
function on(evt, handler2) {
events[evt] = events[evt] || [];
events[evt].push({
handler: handler2
});
}
return {
on: on,
fire: fire
}
})();
EventCenter.fire('roll');
EventCenter.on('roll', function (data) {
console.log(data);
console.log("got you ROLL!!!")
})
模块化写的时候,用于互相呼叫模块可以哦
//工厂模式
function createPerson(opts){
var person = {
name: opts.name||'hunger'
};
person.sayName: function(){
console.log(this.name);
}
return person;
}
var p1 = createPerson({name:'ruoyu'});
var p2 = createPerson({name: '谷'});
工厂模式就是撸一个工具箱,然后大家都可以用这个工具箱做东西
//构造函数模式
function Person(name, age){
this.name = name;
this.age = age;
}
Person.prototype.sayName = function(){
return this.name;
};
var student = new Person("若愚", 30);
console.log(student);
构造函数就是制造一个又一个的函数对象,每一个对象都有同样指针指向的prototype方法
//模块模式
var Person = (function(){
var name = "hunger";
return {
changeName: function(newName){
name = newName;
},
sayName: function(){
console.log(name);
}
};
})();
Person.sayName();
Person.changeName("ruoyu");
Person.sayName();
模块模式和构造函数模式相似,只不过模块模式生成的对象的方法都是每家自有的,不互相污染
//混合模式
var Person = function(name, age) {
this.name = name;
this.age = age;
};
Person.prototype.sayName = function(){
console.log(this.name);
}
var Student = function(name, age, score) {
Person.call(this, name, age);
this.score = score;
};
//Student.prototype = Object.create(Person.prototype);
Student.prototype = create(Person.prototype);
function create (parentObj){
function F(){}
F.prototype = parentObj;
return new F();
};
Student.prototype.sayScore = function(){
console.log(this.score);
}
var student = new Student("谷", 28, 99);
console.log(student);
混合模式可以把几个构造函数模式用.call()连接起来,大家越来越庞大
以上代码如果有不明白的读者同学,欢迎丢入Chrome打断点运行,浏览器给出的解释比啥子注释好用多了。
var events = {};
EventManager = (function () {
function on(evt, handle) {
events[evt] = events[evt] || [];
events[evt].push(handle); //{事件1:[函数1,函数2]}
}
function fire(evt) {
if (!events[evt]) {
console.log("未绑定此事件");
return
}
for (var i = 0; i < events[evt].length; i++) {
events[evt][i]([].slice.call(arguments, 1))
}
}
function off(evt) {
delete events[evt];
}
return {
on: on,
fire: fire,
off: off
}
}());
EventManager.on('text:change', function (val) {
console.log('text:change... now val is ' + val);
});
EventManager.fire('text:change', 'jirengu');//text:change... now val is jirengu
EventManager.off('text:change');
EventManager.fire('text:change', 'jirengu');//未绑定此事件
上面的events要放在上一级作用域下,最后一个.fire才可以打出“未绑定此事件”
代码题
写一个函数createTimer,用于创建计时器,创建的计时器可分别进行计时「新增」。
function createTimer(t) {
var startTime,
endTime,
difference;
function start() {
startTime=Date.now();
return startTime;
}
function end() {
endTime=Date.now();
return endTime
}
function get() {
difference=endTime-startTime;
return difference
}
var timer={
start:start,
end:end,
get:get
};
return timer
}
var timer1 = createTimer();
var timer2 = createTimer();
timer1.start();
for (var i = 0; i < 9999; i++) {
console.error(i);
}
timer2.start();
for (var i = 0; i < 9999; i++) {
console.error(i);
}
timer1.end();
timer2.end();
console.log("一号差距",timer1.get()); //一号差距 527
console.log("二号差距",timer2.get()); //二号差距 232
//封装一个曝光加载组件,能实现如下方式调用
var Expouse = (function () {
function bind($el, fn) {
$(window).on('scroll', function () {
if (!isShow($el)) {
return
}
if (isShow($el)) {
fn.call($el);
}
})
}
function one($el, fn) {
var flag = true;
$(window).on('scroll', function () {
if (flag === false) {
return
}
if (!isShow($el)) {
return
}
if (isShow($el)) {
fn.call($el);
flag = false;
}
})
}
function isShow($el) {
var scrollTop = $(window).scrollTop(),
winH = $(window).height(),
top = $el.offset().top;
if ((scrollTop + winH) > top) {
return true
} else {
return false
}
}
return {
bind: bind,
one: one
}
})()
var $target = $('.target');
Expouse.one($target, function () {
console.log($(this)); // $target
})
封装一个曝光组件