读书笔记-JavaScript面向对象编程(三)

第7章 浏览器环境

7.1 在HTML页面中引入JavaScript代码

7.2概述BOM与DOM(页面以外事物对象和当前页面对象)

7.3 BOM

  7.3.1 window对象再探(所以JavaScript核心函数也都是window对象的方法)

  7.3.2 window.navigator(浏览器信息,如window.navigator.userAgent)

  7.3.3 Firebug的备忘功能

  7.3.4 window.location(当前页面的URL信息,如设置href属性可实现页面跳转)

  7.3.5 window.history(访问页面的历史记录信息,三个方法:forward、back、go)

  7.3.6 window.frames(当前页面中所有frame的集合)

  7.3.7 window.screen(浏览器以外的桌面信息)

  7.3.8 window.open()/close()(打开/关闭新窗口,现已被页面内自定义弹窗代替)

  7.3.9 window.moveTo()/resizeTo()(移动浏览器窗口位置/调整浏览器窗口大小,不建议使用)

  7.3.10 window.alert()/prompt()/confirm()(系统弹窗)

  7.3.11 window.setTimeout()/setInterval()(系统定时器,延时/循环)

setTimeout("alert('boo')",2000);//首参数是一个可以被eval执行的字符串,但应尽量避免
setTimeout(function(){alert('boo')},2000)//推荐:将相关函数调用封装在另一个函数中

  7.3.12 window.document(等同于DOM)

7.4 DOM

  7.4.1 Core DOM与HTML DOM(XML与HTML)

  7.4.2 DOM节点的访问(nodeType、nodeName、nodeValue、documentElement(根节点)、childNodes(子节点集合)、parentNode(父节点)、attributes(节点的属性集合)、textContent(获取节点中的文本内容)、innerHTML)

  (getElementByTagName、getElementByName,getElementById、nextSibling、previousSibling、firstChild、lastChild)

  7.4.3 DOM节点的修改(属性赋值或innerHTML覆盖)

  7.4.4 新建节点(creatElement、creatTextNode并appendChild,或使用innerHTML、choneNode(true/false)、insertBefore)

  7.4.5 移除节点(removeChild,replaceChild,innerHTML设置为‘’)

  7.4.6 只适用于HTML的DOM对象(document.body等价于document.getElementByTagName('body')[0])

  (document.images/applets/links/anchors/forms,document.write,document.cookies/title/referrer/domain)

7.5 事件

  7.5.1 内联HTML属性法

<div onclick="alert('boo!')">click</div>

  7.5.2 元素属性法

<div id="mybtn">click</div>
//以下JS部分
document.getElementById('mybtn').onclick=function(){alert('boo!')}

  7.5.3 DOM的事件监听器(DOM level 2)

var btn=document.getElementById('mybtn');
btn.addEventListener('click',function(){alert('boo!')})

  7.5.4 捕捉法与冒泡法(addEventListener的第三个参数为false只使用冒泡法,stopPropagation阻止冒泡 )

  7.5.5 阻断传播(removeEventListener移除事件,由匿名函数定义的监听器是不能被移除的)

  7.5.6 防止默认行为(preventDefault)

  7.5.7 跨浏览器事件监听器(IE中没有addEventListener用attachEvent,没有target用srcElement,没有stopPropagetion用cancelBubble为true,没有preventDefault用returnValue为false,没有removeEventListener用detachEvent)

  7.5.8 事件类型

7.6 XMLHttpRequest对象

  7.6.1 发送请求

var xhr=new XMLHttpRequest();
xhr.onreadystatechange=myCallback;
xhr.open('GET','somfile.txt',true);
xhr.send('')

   7.6.2 处理响应(当readystate为4时响应返回,继续检测xhr.status服务器返回代码,并进行下一步处理)

  7.6.3 在早于7的IE版本中创建XMLHttpRequest对象 

var xhr=new ActiveXObject('MSXML2.XMLHTTP.3.0');

  7.6.4 A代表异步

  7.6.5 X代表XML

  7.6.6 实例示范

7.7 本章小结

7.8 练习题

 

第8章 编程模式与设计模式

8.1 编程模式

  8.1.1 行为隔离(HTML、CSS与JS隔离,即内容、外观与行为隔离)

  8.1.2 命名空间(只定义一个全局变量,其他变量和方法定义为该变量的属性,很多库都实现的namespace方法如下)

var MYAPP={}
MYAPP.namespace=function(str){
  var parts=str.split('.'),curr=MYAPP;
  for(var i in parts){
    if(!curr[parts[i]]){curr[parts[i]]={}}
    curr=curr[parts[i]]
  }
}
MYAPP.namespace('dom.style');
//等价于如下
var MYAPP={
  dom:{
    style:{}
  }  
}

  8.1.3 初始化分支(根据浏览器特性,一开始判断后再给特定功能函数赋值,当这些功能函数被调用,就用不需要再做探测了,兼容性初始化)

var MYAPP={};
MYAPP.event={
  addListener:null,
  removeListener:null
}
if(typeof window.addEventListener==='function'){
  MYAPP.event.addListener=function(el,type,fn){el.addEventListener(type,fn,false);}
  MYAPP.event.removeListener=function(el,type,fn){el.removeEventListener(type,fn,false);}
}else if(typeof document.attachEvent==='function'){//IE
  MYAPP.event.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);}
  MYAPP.event.removeListener=function(el,type,fn){el.detachEvent('on'+type,fn);}
}else{//older browsers
  MYAPP.event.addListener=function(el,type,fn){el['on'+type]=fn;}
  MYAPP.event.removeListener=function(el,type,fn){el['on'+type]=null;}
}

  8.1.4 延迟定义(同初始化分支。第一次调用时被定义)

var MYAPP={};
MYAPP.myevent={
  addListener:function(el,type,fn){
    if(typeof window.addEventListener==='function'){
      MYAPP.myevent.addListener=function(el,type,fn){el.addEventListener(type,fn,false);}
    }else if(typeof document.attachEvent==='function'){//IE
      MYAPP.myevent.addListener=function(el,type,fn){el.attachEvent('on'+type,fn);}
    }else{//older browsers
      MYAPP.myevent.addListener=function(el,type,fn){el['on'+type]=fn;}
    }
    MAAPP.myevent.addListener(el,type,fn);
  }
}

  8.1.5 配置对象(用于有很多参数的函数,用对象替代参数可以不考虑参数顺序,跳过默认值,扩展性更强,可读性更好)

  8.1.6 私有属性和方法(对象方法内部定义的局部变量和函数)

  8.1.7 特权函数(建立公共函数,它们可以访问内部私有属性和方法,如get/set方法)

  8.1.8 私有函数的公有化

var MYAPP={};
MYAPP.dom=(function(){
  var _setStyle=function(el,prop,value){console.log('setstyle')}
  var _getStyle=function(el,prop){console.log('getstyle')}
  return {
    setstyle:_setStyle,
    getstyle:_getStyle,
    yetAnother:_setStyle
  }
})()
MYAPP.dom.setstyle=function(){alert('b')}//外部可以改写setstyle方法,yetAnother依然指向_setStyle

  8.1.9 自执行函数(保证命名空间,特别适合执行一次性初始化任务)

  8.1.10 链式调用(前一个方法的结果(即返回对象)来调用下一个方法)

  8.1.11 JSON

8.2 设计模式

  8.2.1 单件模式1

var single={};//最基本的单件模式

  8.2.2 单件模式2(仅生成一个对象)

function Logger(){
  if(typeof global_log==='undefined'){global_log=this;}
  return global_log;
}
var a=new Logger();
var b=new Logger();
alert(a===b);//true,此方法产生全局变量global_log
var Logger=(function(){
  var instance=null;
  return {
    getinstance:function(){
      if(instance==null){instance=this};
      return instance;
    }
  }
})()
var a=Logger.getinstance();
var b=Logger.getinstance();
alert(a===b);//true,利用只执行函数和闭包来实现

   8.2.3 工厂模式(创建对象模式)

//假如我有三个不同的构造器,它们功能相似,但处理细节不同
var MYAPP={};
MYAPP.dom={};
MYAPP.dom.Text=function(){
  this.insert=function(where){
    var txt=document.createTextNode(this.url);
    where.appendChild(txt)
  }
};
MYAPP.dom.Link=function(){
  this.insert=function(where){
    var link=document.createElement('a');
    link.href=this.url;
    link.appendChild(document.createTextNode(this.url));
    where.appendChild(link)
  }
};
MYAPP.dom.Image=function(){
  this.insert=function(where){
    var img=document.createElement('img');
    img.src=this.url;
    where.appendChild(img)
  }
};
//使用三个构造器的方法都一样,设置URL属性并调用insert方法
var t=new MYAPP.dom.Text();
t.url='http://www.baidu.com/1.jpg';
t.insert(document.body)
//如果我们暂时不知道创建哪种对象,需要根据用户触发按钮来决定,按钮提供type表示创建类型,如下
var o;
if(type ==='Text'){o=new MYAPP.dom.Text();
}else if(type ==='Link'){o=new MYAPP.dom.Link();
}else if(type ==='Image'){o=new MYAPP.dom.Image();}
o.url='http://...';
o.insert();
//添加工厂方法factory,避免如上判断
MYAPP.dom.factory=function(type){return new MYAPP.dom[type];}
var o=MYAPP.dom.factory(type);
o.url='http://...';
o.insert();

  8.2.4 装饰者模式(结构性模式,主要拓展对象的功能)

//装饰者模式实例:装饰一颗圣诞树
var tree={
  decorate:function(){console.log('确保树不会倒');}
};
//接着定义方法用于添加额外的装饰器,装饰器实现为构造器函数,都继承tree
tree.getDecorate=function(deco){tree[deco].prototype=this;return new tree[deco];}//让每一个装饰后对象的原型等于父级
//下面创建装饰器,将他们设置为tree的属性(保证命名空间),它们提供decorate方法,单先调用父类的decorate
tree.RedBalls=function(){
  this.decorate=function(){this.RedBalls.prototype.decorate();console.log('上面放一些红球')}
}
tree.BlueBalls=function(){
  this.decorate=function(){this.BlueBalls.prototype.decorate();console.log('下面放一些蓝球')}
}
tree.Angel=function(){
  this.decorate=function(){this.Angel.prototype.decorate();console.log('在树顶放一个小天使')}
}
//再把所有的装饰器都添加到基础对象上
tree=tree.getDecorate('BlueBalls')
tree=tree.getDecorate('Angel')
tree=tree.getDecorate('RedBalls')
tree.decorate();
//tree.Redballs的原型为父类tree.Angel的原型为父类tree.RedBalls的原型为父类tree(初始状态)
console.log(tree.getDecorate('BlueBalls').getDecorate('Angel').getDecorate('RedBalls'))

  8.2.5 观察者模式(行为模式,主要用于处理不同对象间的交互通信)

//先创建一个观察者,它包含由回调函数构成的订阅者数组,用于增加和删除订阅者的方法,publish授受并传递数据给订阅者,make将任意对象转变为发行商并添加上述方法
var observer={
  addSubscriber:function(callback){this.subscribers[this.subscribers.length]=callback;},
  removeSubscriber:function(callback){
    for(var i=0; i<this.subscribers.length;i++){if(this.subscribers[i]==callback){delete(this.subscribers[i])}}
  },
  publish:function(what){
    for(var i=0; i<this.subscribers.length;i++){if(typeof this.subscribers[i]==='function'){this.subscribers[i](what)}}
  },
  make:function(o){
    for(var i in this){o[i]=this[i];o.subscribers=[]}
  }
}
//接下来我们创建一些订阅者,它们可以是任意对象,唯一职责就是在发生重要事件时调用publish方法
var blogger={
  writeBlogPost:function(){var content='今天是'+new Date();this.publish(content);}
}
var latimes={
  newIssue:function(){var paper='火星人来地球了!';this.publish(paper);}
}
//它们都很容易转变为发行商
observer.make(blogger);
observer.make(latimes);
//于此同时,准备两个简单对象
var jack={
  read:function(what){console.log('我刚看了'+what)}
}
var jill={
  gossip:function(what){console.log('你没听到我的话,但'+what)}
}
//将他们订阅blogger,只需要提供事件发生时的回调函数
blogger.addSubscriber(jack.read);
blogger.addSubscriber(jill.gossip);
//当blogger写了新的博客时,jack和jill都会收到通知
blogger.writeBlogPost();
//任何时候jill都可以取消订阅,再推送时将不再收到通知
blogger.removeSubscriber(jill.gossip);
blogger.writeBlogPost();
//jilly也可以订阅latimes,因为一个订阅者可以对应多个发行商
latimes.addSubscriber(jill.gossip);
latimes.newIssue()

 --完--

 

posted @ 2017-01-12 15:58  小古哥  阅读(307)  评论(0编辑  收藏  举报