花了一个星期看完了这本书,把随笔写一写,还摘录了一些书里封装好的函数,偶尔多看看(只捡了感觉重要的东西)
HTML(Model)+CSS(View)+javascript(Controller)
怪异模式是因为DTD触发,也就是 Document Type Definition (文档定义类型) <!DOCTYPE html>
多种组织CSS方式 例如可以按功能划分 font.css color.css layout.css
此书推荐base.css(通用层)+common(网站级)+css+page(页面级).css 将网站内的所有样式,按照职能划分为三大类:base common page
如果页面里的功能需求很简单,页面里可以没有base层代码,可以没有common层代码,但一定会有page层代码。base层和common层都是属于框架级的,page层是属于应用级的,它可以调用base层得接口和common层的组件。
base和common就是接口接口接口,底层接口
base就像是把一条路捋平了,common就是把路铺上沥青,page就是一辆小车车,然后就让它飞奔起来~~~
HTML规范:
DTD统一用<!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/><html/DTD/><html1-transitional.dtd">
HTML应当在保证弹性的基础上尽量减少嵌套层数。
严格区分作为内容的图片和作为背景的图片。作为背景的图片采用CSSsprite技术,放在一张大图里。大图的安排也遵从common+app的方式,全站采用的图片应告知公用组件维护者,添入common.gif中,各栏目的图片,应放入app.gif中。CSS sprite技术的优点是减少了http请求数,但使图片面向CSS的background-position增加了耦合度,也增加了维护成本。如果图片有修改,不要删除已添加的图片,在空白处新增修改后的图片,减少修改风险。
CSS规范:
CSS Reset用YUI的CSS Reset
CSS采用CSSReset+common .css+app.css
为避免组件的上下外边距重合问题和IE的haslayout引发的Bug,各模块除特殊需求,一律采用marginTop设置上下外边距,如下栗子:
<p>000000000</p>
<p class="marginTop10 marginBottom10">00000000</p>
<p>000000</p>
错误
<p>000000000</p>
<p class="marginTop10">00000000</p>
<p class="marginTop10">000000</p>
正确
CSS用一行的写法,避免函数太长,不利于查找
--------------------------JS----------------------
(function(){})():
用匿名函数将脚本包起来,可以有效控制全局变量,避免冲突隐患;
window.onload事件:window对象会在网页内元素全部加载完毕之后触发onload事件
但是会存在一个问题,window的onload事件要求网页内所有的元素全部加载完毕后才会触发。
可以使用JS框架提供的DOMReady事件代替window.onload,作用很像,但是DOMReady只判断页面内所有的DOM节点是否已经全部生成,然后就触发加载。
CSS放在页头,JavaScript放在页尾
还有如果非要放在页头
那么CSS文件一定要再JS文件前面,JS容易阻塞网页
JS的分层也跟CSS的分层差不多
从下往上依次是base层,common层,page层
base层得JavaScript和页面里的具体应用逻辑无关,是属于框架级的,它提供的接口需要供全局作用域调用。
尽量使用命名空间来减少全局作用域变量的个数
原生读取cookie时一件非常痛苦的事!cookie无法直接读取某个键中保存的值,只能从ducument.cookie中将所有的键值对全部读出来,再使用split,indexOf,slice等方法操作字符串截取自己需要的键的值!
为了方便分辨class是用于css的挂钩还是JavaScript的挂钩,我们可以给用于JavaScript的class加上“J_”作为前缀;
DRY规则----don‘t repeat yourself(程序中不要将相同的代码重复编写多次)
在对函数传参时,有普通传参这种方式,但是可以使用hash对象传参的方式,这样可以避免不用把不需要的参数传进去,还非得设置null这样的数值;
下面举个栗子:
//普通方式传参
function test(a,b,c){
var oA=a||1,oB=b||2,oC=c||3;
}
test(4,5,6) ;
test(null,7,8);
test(null,null,9);
//用hash对象传参
function test2(config)
{
var oA=config.a||1,oB=config.b||2,oC=config.c||3;
}
test({a:4,b:5,c:6});
test2({b:7,c:8});
test2({c:9});
使用hash对象传参,可以提高函数调用的灵活性,提高函数扩展性。
面向过程的思维方式是典型的计算机思维方式---输入数据给处理器,处理器内部执行运算,处理器返回结果。
面向过程的方式编程
var name="adang";
var state="awake";
var say=function(oName){
alert("I‘m"+oName);
}
var sleep=function(oState){
oState="asleep";
}
say(name);
sleep(state);
面向对象方式编程
var adang={
name:"adang",
state:"awake",
say:function(){
alert("I‘m"+this.name);
},
sleep:function(){
this.state="asleep";
}
};
adang.say();
adang.sleep();
属性本质其实是个变量,也就是面向过程中的数据,而行为的本质其实是函数,也就是面向过程的处理函数。不同的是,面向过程中,数据和处理函数并没有关联起来,共同属于某个物件。而面向对象将数据和处理函数定义到了一个对象的内部,作为这个对象的属性和行为存在。在对象外部,属性和行为可以用对象的属性和对象的行为来调用,从而让程序有了按真实世界的思维方式进行描述的能力。在对象内部,对象的属性和行为通过this关键字关联起来。
面向过程编程所有的数据和处理函数都是公有的,整个编程的思维过程就是定义数据,定义处理函数,然后将数据传给处理函数进行处理,处理函数之间也可以互相调用,数据和处理函数紧密耦合。面向对象编程的思维过程是定义一个个对象,对象有自己的属性和行为,因为属性和行为都是从属对象,于是有了“对象内”和”对象外“的概念,整个程序可以油一堆对象组成,对象与对象之间可能会有通信,为了实现这种通信,对象会将自己的部分属性和行为设计成公有,暴露出来成为通信的接口。对象和对象之间的通信都是建立在接口的基础上的。当然我们可以将对象所有的属性和行为都设为公有的,全部都作为接口,但接口越多,会让对象之间耦合越紧密,增加维护难度,所以一般情况下,我们都会尽量将对象的属性和方法设为私有,只讲必要的行为设为公有。
面向对象英文全称Object Oriented ,简称OO。OO其实包括OOA(Object Oriented Analysis ,面向对象分析),OOD (Object Oriented Design,面向对象设计)和OOP(Object Oriented Programming,面向对象的程序设计)。
一个典型的OO编程过程应该是先整理需求,根据需求进行OOA,将真实世界的客官物件抽象成哼程序中的类或对象,这个过程经常会用到的是UML语言,也称UML建模,OOA的输出结果是一个个类或对象的模型图。然后就用OOD,这里一般是为了处理类之间耦合关系,设计类或对象的接口,此时会用到各种设计模型,例如观察者模式,责任链模式等。OOA和OOD是个反复迭代的过程,它们本身没有非常清晰的边界,是互相影响,制约的。等OOA和OOD结束之后,才到OOP,进行实际的编码工作。OOA和OOD是面向对象编程的思想和具体语言无关,而OOP是面向对象编程的工具,和选用的语言相关。OOP是OOA和OOD的底层,不同原因的语法不同,所以OOP不同,但OOA和OOD与具体要求语言无关,一般情况下可以轻易跨语言重用。
但实际上呢,一个OOA能力是非常重要的,OOP一般是用不到那么复杂的设计,OOP只占了一小部分的时间
“高内聚,低耦合”聚合指的是把一个复杂的事物看成若干个比较简单的事物的组装提,从而简化对复杂事物的描述,“高内聚”就是指对象(或类)对外提供的接口非常简单易懂,复杂的底层操作都封装在对象(或类)的接口内部,对用户透明。耦合指的是类与类之间关联和依赖的程度,低耦合就是指类与类之间依赖的程度低,类与类通信需要关联的接口越少,耦合程度越低。
决定聚合和耦合程度的是OOA和OOD,OOA和OOD是工作在架构层面的,而OOP是工作在编码层面的。从大局上决定程序品质的,不是OOP,而是OOA和OOD,这是很多工程师要注意的。
原来JavaScript也有类
//函数作为普通函数
function sayHi(){
alert("hi");
}
sayHi();
//函数作为类
function Animal(name){
this.name=name;
this.type="animal";
this.say=function(){
alert("I‘m a(an) "+this.type+",my name is "+this.name);
}
}
var myDog=new Animal("wangcai");
myDog.say();
这样的实例方法,然后实例后就是Animal类;
实例化类时JavaScript和C#这种正统面向对象语言并没有明显差别,差别主要在类的定义方式上面。
JavaScript是基于原型的语言
通过new实例化出来的对象,其属性和行为来自于两部分,一部分来自于构造函数,另一部分来自于原型。什么事原型呢?当我们声明一个类时,其实同时生成一个对应的原型,例如我们定义Animal这个类时,会生成一个与Animal类对应的原型,通过Animal.prototype可以指向这个原型,原型可以通过constructor指向Animal类,更确切地说,是指向Animal类的构造函数。
栗子:
//定义Animal类的构造函数
function Animal(){
....
}
var a=Animal.prototype; //a指向Animal类对应的原型
var b=a.constructor; //b指向a对应的类的构造函数
alert(b==Animal) //true
this关键字,可以让属性和方法在构造函数和原型间通信。
在JavaScript中公有还是私有是通过作用域实现的。
this×××定义的属性是公有的,而用var×××定义的属性是私有的
将所有的属性和行为,无论公有还是私有全部写在构造函数虽然方便,但是不推荐这么做,因为在内存中一个类的原型只有一个,写在原型中的行为,可以被所有实例所共享,实例化的时候,并不会在实例的内存中再复制一份,也就是说所有实例共用那个内存了,而写在类里的行为,实例化的时候回在每个实例里复制一份;
把行为写在原型里可以减少内存消耗,没有特殊原因,推荐尽量把行为写在原型里,写在原型中的行为一定是公有的,而且无法访问私有属性,所以如何处理私有行为和私有属性是个难题。
在原型中定义私有行为,但通过给属性和行为的名称前面加上“_”来约定它是私有的,这是一种命名约定,它并不能真正实现行为的私有,但它可以让工程师知道它是设计成私有的,从而避开像公共行为那样调用它
属性就写在构造函数中,行为方法就写在原型中
避免直接访问类的属性,可以通过get和set方法来获取和设置属性
function Animal(name){
var name;
this.getName=function(){
return name;
}
this.setName=function(o){
name=o;
}
}
//然后实例化后就可以调用getName获取对应属性值了,setName就可以设置属性值
这么做会占用很多内存,但是它可以更好的保护属性
只要是类就会有原型,不管它是自定义类还是JavaScript的内置类,我们可以通过修改内置类的原型,让JavaScript基本类型的对象获取一些有趣的功能。
无论在类的构造函数中还是原型中,this都指向实例化的对象。
拓展Array的例子,
修改内置类的原型:Array.prototype.each=function(fun){
for(var i=0,n=this.length;i<n;i++){
fun(this[i],i);
}
}
var a=[1,2,3];
alert(a); //1,2,3
Array.prototype.toString=function(str){
return "I‘m an array";
}
alert(a); //I‘m an array
值得一提的是,“alert(a)”时,自动调用了a的toString方法。在需要字符串时,对象会隐式地自动调用toString方法,包括我们自定义的对象。内置类的方法可以重写,但属性却不能重写
给自定义类定义toString方法,可以为我们在调试时提供更多有用的信息。
在JavaScript中,包括内置类和自定义类,所有的类的祖先类都是Object,所以如果想对所有对象都拓展方法,可以通过修改Object类的原型实现
使用JavaScript对HTML标签属性操作:
class是JavaScript的保留字,所以在获取HTML标签的class属性时,要改用className。
使用node.×××的方式获取常规HTML标签的属性值,跨浏览器兼容性比node.getAttribute("×××")好。
要注意的是,自定义标签属性同样可以再JavaScript中获取,但是和常规属性不同,Firefox下无法通过node.×××获取到自定义属性值,只能使用node.getAttribute("×××")获取,IE下面就可以哦~!
将复杂类型的数据转化成字符串,就称为数据的序列化,其逆操作就是反序列化。
字符串的反序列化是通过eval函数实现的。只要字符串长得像JavaScript支持的数据格式(json),就可以进行反序列化,而与是不是Ajax的返回数据无关。
-----------------------------------------------------------------错误------------------------------
1.tabContents[i] is undefined(在遍历数组时对DOM监听事件,索引值始终等于遍历结束后的值)
解决方案:
1)利用闭包
2)给DOM节点添加index属性,属性值就等于索引,(可以应用在轮播图中各个按钮与图片的关联)
2.IE下面JS的this指向问题 "‘tabContents[...].style‘为空或不是对象"。(JavaScript伪协议和内联事件度this的指向不同)
1)使用匿名函数可以解决这个问题哦!
2)使用call和apply调整this指向(只知道这玩意是继承那的,不知道怎么调整)
什么是事件冒泡
在一个对象上触发某类事件(比如单击onclick事件),如果此对象定义了此事件的处理程序,那么此事件就会调用这个处理程序,如果没有定义此事件处理程序或者事件返回true,那么这个事件会向这个对象的父级对象传播,从里到外,直至它被处理(父级对象所有同类事件都将被激活),或者它到达了对象层次的最顶层,即document对象(有些浏览器是window)。
------------摘录了几个封装好的函数--(敲的好辛苦啊)-------------
//透明度问题 利用js代码解决IE下的透明度问题
function setOpacity(node,level){
node=typeof node==="string"?document.getElementById(‘node‘):node;
if(document.all)
{
node.style.filter=‘alpha(opacity=‘ + level + ‘)‘;
}else{
node.style.opacity=level/100;
}
}
//阻止事件冒泡
function stopPropagation(e){
e=window.event||e;
if(document.all)
{
e.cancelBubble=true;
}else{
e.stopPropagation();
}
}
//去除字符串首尾的空白字符
function trim(ostr){
return ostr.replace(/^\s+|\s+$/g,"");
}
//类型判断
function isNumber(s){
return !isNaN(s);
}
function isString (s) {
return typeof s==="string";
}
function isBoolean(s){
return typeof s==="Boolean";
}
function isFunction(s){
return typeof s==="function";
}
function isNull(s){
return s===null;
}
function isUndefined(s){
return typeof s==="undefined";
}
function isEmpty(s){
return /^\s*$/.test(s);
}
function isArray(s){
return s instanceof Array;
}
//第一个参数是class名,第二个参数是父容器,缺省为body节点,第三个参数为DOM节点的标签名。
function getElementSByClassName(str,root,tag){
if(root){
root=typeof root=="string" ?document.getElementById(root):root;
}else{
root=document.body;
}
tag=tag||"*";
var els=root.getElementsByTagName(tag),arr=[];
for(var i=0,n=els.length;i<n;i++){
for (var j=0,k=els[i].className.split(" ");,l=k.length;j< 1; j++){
if(k[j]==str){
arr.push(els[i]);
break;
}
}
}
return arr;
}
//继承功能
function extend(subClass,superClass){
var F=function(){};
F.prototype=superClass.prototype;
subClass.prototype=new F();
subClass.prototype.constructor=subClass;
subClass.superClass=superClass.prototype;
if(superClass.prototype.constructor==Object.prototype.constructor){
superClass.prototype.constructor=superClass;
}
}
//Cookie的操作
GLOBAL.namespace("Cookie");
GlOBAL.Cookie={
//读取
read:function(name){
var cookieStr="; "+document.Cookie+"; ";
var index=cookieStr.indexOf("; "+name+"=");
if(index!=-1){
var s=cookieStr.substring(index+name.length+3,cookieStr.length);
return unescape(s.substring(0,s.indexOf("; ")));
}else{
return null;
}
};
//设置
set:function(name,value,expires){
var expDays=expires*24*60*60*1000;
var expDate=new Date();
expDate.setTime(expDate.getTime()+expDays);
var expString=expires ? ";expires ="+expDate.toGMTString() : "";
var pathString=";path=/";
document.Cookie=name + "=" +escape(value) + expString +pathString;
};
// 删除
del:function(name){
var exp=new Date(new Date().getTime()-1);
var s=this.read(name);
if(s!=null) {
document.cookie=name+"="+s+";expires="+exp.toGMTString()+";path=/"
};
}
};
//封装起来的命名空间函数,为了解决冲突命名
var GLOBAL={};
GLOBAL.namespace=function(str){
var arr=str.split("."),o=GLOBAL;
for(i=(arr[0]=="GLOBAL")?1:0;i<arr.length;i++){
o[arr[i]]=o[arr[i]]||{};
o=o[arr[i]];
}
}
Web前端开发修炼之道--笔记