Object-Oriented JavaScript笔记(七)

Object-Oriented JavaScript 笔记
Object-Oriented JavaScript笔记(一)
Object-Oriented JavaScript笔记(二)
Object-Oriented JavaScript笔记(三)
Object-Oriented JavaScript笔记(四)
Object-Oriented JavaScript笔记(五)
Object-Oriented JavaScript笔记(六)
Object-Oriented JavaScript笔记(七)

第八章 编码和设计模式

编码模式

  • Separating behavior
  • Namespaces
  • Init-time branching
  • Lazy definition
  • Configuration objects
  • Private variables and methods
  • Privileged methods
  • Private functions as public methods
  • Self-executable functions
  • Chaining
  • JSON

分离行为

内容与展现,行为分离

HTML:
1.尽可能的不使用style属性
2.与展现相关的tag都不应该被使用,如
3.根据语义使用相关的tag

行为:
1.尽可能减少script标签的数量
2.避免内联的事件(DOM Level 0)
3.不要使用CSS表达式
4.不影响禁用脚本的用户
5.在body标签闭合前引入脚本

命名空间
避免使用全局变量名以降低命名冲突的可能性。
为了简化编码,可以提供一个namespace()方法用于构造命名空间。

分支(条件)初始化
避免在运行时做特性嗅探,在初始化时候先嗅探再初始化相关函数。

惰性定义(延迟定义)
跟条件初始化类似,在需要使用到的时候再完成实际的函数定义工作。

参数对象化
使用对象的形式来传参数。
虽然JS支持可变参数,但是参数对象化后可以不用记住参数顺序,而且方便以后扩展。

私有属性及方法
内部属性和方法别让外部修改。

特权方法
用它来访问私有属性和方法。

将私有方法公开

自启动

var MYAPP = {};
MYAPP.dom = function(){
     // initialization code...
     function _private(){
     // ... body
     }
     return {
          getStyle: function(el, prop) {
          console.log('getStyle');
          _private();
          },
          setStyle: function(el, prop, value) {
          console.log('setStyle');
          }
     };
}();

链式调用
返回this

使用JSON
PS:原文中这节的示例代码是使用的单引号,这是十分不好的,应该避免。虽然在JS中单双引号等效,但标准中指明了是使用双引号。

设计模式

分三类:创建模式、结构模式和行为模式

  • 单例模式 Singleton
  • 工厂模式 Factory
  • 装饰模式 Decorator
  • 观察者模式 Observer

-EOF-

Object-Oriented JavaScript笔记(六)

Object-Oriented JavaScript 笔记
Object-Oriented JavaScript笔记(一)
Object-Oriented JavaScript笔记(二)
Object-Oriented JavaScript笔记(三)
Object-Oriented JavaScript笔记(四)
Object-Oriented JavaScript笔记(五)
Object-Oriented JavaScript笔记(六)
Object-Oriented JavaScript笔记(七)

第七章 浏览器环境

文档对象模型(处理当前页面内容的)与浏览器对象模型(处理当前页面之外的)
参考资料:

* The Mozilla DOM reference for Firefox information
* Microsoft’s documentation for Internet Explorer
* W3C’ DOM specs

BOM
提供一组对象访问浏览器(window)及计算机屏幕信息(window.screen)

window对象相关属性
window.navigator 包含浏览器及其功能信息
navigator.userAgent 返回浏览器标识信息,开发者常用它区分浏览器以提供不同的实现代码

if (navigator.userAgent.indexOf('MSIE') !== -1) {
     // this is IE
   } else {
     // not IE
}

这并不能完整的细分到每一个浏览器,更好的办法是使用特性嗅探法

if (typeof window.addEventListener === 'function') {
     // feature is supported, let's use it
   } else {
     // hmm, this feature is not supported, will have to
     // think of another way
}

window.location 提供与当前页面url有关的信息,同时提供了三个方法reload(), assign() 和 replace().
assign和replace功能很相似,区别是replace不在window.history中产生信息。

window.history允许你访问当前会话窗口的访问历史

window.frames保存一组当前页面的frames信息,无论是否存在frames,window.frames总是指向window对象(这说明它也是一个伪数组)
每个frame中都包含一个独立的window对象,可以通过下面几种形式访问它
>>> window.frames[0]
>>> window.frames[0].window
>>> frames[0].window
>>> frames[0]

父页面可以访问子页面,子页面同样可以访问父页面,每个页面都有一个window.parent指向其父页面(不存在时指向自身)
如果要访问顶层页面,window.top (不存在时指向自身)

如果一个frame有name属性,也可以通过name访问它window.frames[‘myframe’]

window.screen提供屏幕与颜色深度信息

window.open()/window.close()/window.moveTo()/window.resizeTo()/window.alert()/window.prompt()/window.confirm()这些别用了。

注意:alert()并不是ECMAScript中定义的方法。

window.setTimeout(), window.setInterval()延时执行和重复执行
虽然第一个参数可以传字符串setTimeout(‘foo’,2000)但是还是别传字符串,传函数引用更妥当setTimeout(foo,2000)

window.document提供当前页面文档对象模型相关的信息(DOM)

nodeType为1的节点(element nodes),nodeName和tagName都是节点的标签名称。

innerHTML并不是标准中存在的,但所有的浏览器都支持它。

document.getElementsByTagName(‘*’)
早期的IE浏览器并不支持星号作为tag名称传入,不过可以使用document.all获得所有元素。
IE7开始支持*号作为标签名,但它会返回所有节点,而不仅仅只是元素类节点。

遍历dom

function walkDOM(n) {
 do {
   console.log(n);
   if (n.hasChildNodes()) {
     walkDOM(n.firstChild)
   }
 } while (n = n.nextSibling)
}
walkDOM(document.body)

CSS中的短横线在JavaScript并不是合法的名字,所以margin-left在在js中是以el.style.marginLeft的形式访问。
可以直接修改节点的属性,如
el.id = ‘sidebar’
由于class在JavaScript中是保留字,修改class属性则使用el.className

HTML 私有对象
document.images 等效于 document.getElementsByTagName('img')

document.applets 等效于 document.getElementsByTagName ('applets')

document.links 所有的

document.anchors 所有的

document.forms

非核心对象
document.cookie
document.title
document.referrer
document.domain
document.location

注意,改变document.title并不等效于访问document.getElementsByTagName(' title')[0],它只是更改浏览器窗口上的显示。

document.referrer的值等同于http头里的Referer(由于历史原因,这是个拼写错的词)

document.domain可以从小域改称大域(www.yahoo.com -> yahoo.com),但不能从大域改称小域(yahoo.com -> www.yahoo.com),常用于解决跨域问题。

window.location === document.location

事件
在2级DOM事件模型中,事件传播分三个阶段进行,即捕获阶段(capturing)、目标阶段和冒泡阶段(bubbling)。

IE 只支持冒泡
Netscape 只支持捕获

var mypara = document.getElementById('my-div');
mypara.addEventListener('click', function() {alert('Boo!')}, false);

第三个参数决定是否使用捕获,由于兼容性原因,建议传false,在实际的使用中只使用冒泡。

可以使用e.stopPropagation();放弃冒泡。
事件代理(event delegation)的应用

IE中还是可能使用事件捕获的 setCapture() / releaseCapture(),但它只支持鼠标事件,其它事件(如键盘事件)则不支持。

window.addEventListener('click', function(){alert ('clicked window')}, false);
window.attachEvent('click', function(){alert ('clicked window')}, false);

DOM 规范中并没有说事件绑在window上会怎么样,在IE中(注:低版本)并不会触发,在Firefox中会出发。

移除一个事件,需要传入原事件指针,故绑的匿名函数不能被移除掉。

para.removeEventListener('click', paraHandler, false);

终止默认事件
e.preventDefault();

并不是所有事件的默认行为都能被终止,可以检查事件对象的cancellable字段来确认。

IE中事件不同的部分:

1.(低版本的)IE没有addEventListener() 但IE5开始它有个等价的 attachEvent()方法
2.attachEvent()中click要写作onclick
3.使用老式方法(onclick)时,回调函数并不会传入event参数,但会有个全局的window.event供使用(注:现实场景中它需要先cache下来)
4.IE的事件没有target属性用于指示目标函数,但有个等价的srcElement
5.并不是素偶有的事件都有捕获截断,所以只能使用冒泡
6.没有stopPropagation()方法,但是可以设置cancelBubble 属性值为true
7.没有preventDefault()方法,但是可以设置returnValue值为false
8.removeEventListener()的等效方法detachEvent().

兼容性示例:

function callback(evt) {
     // prep work
     evt = evt || window.event;
     var target = (typeof evt.target !== 'undefined') ? evt.target : evt.srcElement;
     // actual callback work
     console.log(target.nodeName);
}
// start listening for click events
if (document.addEventListener){ // FF
     document.addEventListener('click', callback, false);
} else if (document.attachEvent){ // IE
     document.attachEvent('onclick', callback);
} else {
     document.onclick = callback;
}

事件类型

鼠标事件:
mouseup, mousedown, click (the sequence is mousedown-up-click), dblclick

mouseover (mouse is over an element), mouseout (mouse was over an element but left it), mousemove

键盘事件:
keydown, keypress, keyup (occur in this sequence)

载入\window事件:
load (an image or a page and all of its components are done loading), unload (user leaves the page), beforeunload (the script can provide the user with an option to stop the unload)
abort (user stops loading the page in Firefox or an image in IE), error (a JavaScript error in Firefox and IE, also when an image cannot be loaded in IE)
resize (browser window is resized), scroll (the page is scrolled), contextmenu (the right-click menu appears)

表单事件:
focus (enter a form field), blur (leave form field)
change (leave a field after the value has changed), select (select text in a text field)
reset, submit

AJAX(XMLHttpRequest以及IE7之前使用ActiveXObject)
-EOF-

Object-Oriented JavaScript笔记(五)

Object-Oriented JavaScript 笔记
Object-Oriented JavaScript笔记(一)
Object-Oriented JavaScript笔记(二)
Object-Oriented JavaScript笔记(三)
Object-Oriented JavaScript笔记(四)
Object-Oriented JavaScript笔记(五)
Object-Oriented JavaScript笔记(六)
Object-Oriented JavaScript笔记(七)

第六章 继承

空的构造函数—new F()
用于解决原型链上的属性被覆盖的问题。

var extend = function(origin, target){
     var F = function(){};
     F.prototype = origin.prototype;
     target.prototype = new F();
     target.prototype.constructor = target;
};

var A = function(){};
A.prototype.name = 'A';
A.prototype.toString = function(){ return this.name};

var B = function(){};
extend(A,B);
B.prototype.name = 'B';

/*
var a = new A();
var b = new B();
b instanceof B
true
b instanceof A
true
a instanceof A
true
a instanceof B
false
*/

Uber 访问父方法。

var extend = function(origin, target){
     var F = function(){};
     F.prototype = origin.prototype;
     target.prototype = new F();
     target.prototype.constructor = target;
     target.uber = origin.prototype;
};

var A = function(){};
A.prototype.name = 'A';
A.prototype.toString = function(){
     var result = [];
     if (this.constructor.uber){
          result[result.length] = this.constructor.uber.toString();
     }
     result[result.length] = this.name;
     return result.join(', ');
};
A.prototype.show = function(){
     console.log('A show');
};
var B = function(){};
extend(A,B);
B.prototype.name = 'B';
B.prototype.show = function(){
     this.constructor.uber.show();
     console.log('B show');
};
/*
var a = new A();
var b = new B();
b instanceof B
true
b instanceof A
true
a instanceof A
true
a instanceof B
false
*/

用函数来实现继承 (注:实际上上面的两个示例的extend已经是被我封装过的了)

var exntend = function(Child, Parent){
     var F = function(){};
     F.prototype = Parent.prototype;
     Child.prototype = new F();
     Child.prototype.constructor = Child;
     Child.uber = Parent.prototype;
};

复制属性

function extend2(Child, Parent) {
     var p = Parent.prototype;
     var c = Child.prototype;
     for (var i in p) {
          c[i] = p[i];
     }
     c.uber = p;
}

当复制引用带来的问题

修改引用对象会导致原型的也被修改。

从对象中继承:

浅拷贝

function extendCopy(p) {
     var c = {};
     for (var i in p) {
     c[i] = p[i];
     }
     c.uber = p;
     return c;
}

深拷贝:

function deepCopy(p, c) {
     var c = c || {};
     for (var i in p) {
          if (typeof p[i] === 'object') {
               c[i] = (p[i].constructor === Array) ? [] : {};
               deepCopy(p[i], c[i]);
          } else {
               c[i] = p[i];
          }
     }
     return c;
}

object()构造起,老道提议的形式。

function object(o) {
     function F() {}
     F.prototype = o;
     return new F();
}

混合原型拷贝和属性继承(很多时候需要继承一个对象,并给它添加一些属性用)

function objectPlus(o, stuff) {
     var n;
     function F() {}
     F.prototype = o;
     n = new F();
     n.uber = o;
     for (var i in stuff) {
     n[i] = stuff[i];
     }
     return n;
}

多重继承,说白了就是按顺序进行属性复制,后出现的覆盖已经存在的。

function multi() {
     var n = {}, stuff, j = 0, len = arguments.length;
     for (j = 0; j < len; j++) {
          stuff = arguments[j];
          for (var i in stuff) {
               n[i] = stuff[i];
          }
     }
     return n;
}

-EOF-

Chrome For Mac 离线安装包下载

以前写过一篇Chrome离线安装包下载方法是用于Windows的,今天重装了Mac,由于最新的版本不稳定,所以还是下载老版本。网上其它站点下载的不可信,得从Google官方的站点下才行,终于,偶还真把 Google Chrome 18.0.1025.168这个版本给下载下来了。
实际下载地址:

http://dl.google.com/chrome/mac/GoogleChrome-18.0.1025.168.dmg

Chrome Releases Blog查到对应的版本号,替换即可。
-EOF-