当前位置:首页 > 新闻动态 > 网站文章

电子商务网站开发与建设

来源: 浏览:152 时间:2023-09-19

概要

64学时 3.5学分

章节安排

  1. 电子商务网站概况
  2. HTML5+CSS3
  3. JavaScript
  4. Node

电子商务网站概述

电子商务网站定义

电子商务网站是指一个企业、机构或公司在互联网上建立的站点,其目的是为了宣传企业形象、发布产品信息、宣传经济法规、提供商业服务等。

电子商务网站功能

  • 企业形象宣传

  • 新闻发布、供求信息发布

  • 产品和服务项目展示

  • 商品和服务定购

电子商务网站的架构

电子商务网站的构成要素

  • 网站域名
  • 网站物理地点
  • 网站页面
  • 商品目录
  • 购物车
  • 付款台

JavaScript

  • 基础语法

  • 客户端JavaScript

基础语法

  • 词法结构

  • 类型、变量、运算符和表达式

  • 语句

  • 数组

  • 函数

  • 对象

  • 类和模块

  • 正则表达式的模式匹配

词法结构

JavaScript是区分大小写的语言。

JavaScript支持2种格式的注释:

//这里是单行注释
/*这里是一段注释(这里的注释可以连写多行)*/
_$
breakdeletefunctionreturntypeofcasedoifswitchvarcatch
;

类型、变量、运算符和表达式

JavaScript的数据类型分为2类:

nullundefined

数字、算术运算符

数字:包括整数、浮点数。

+-*/%++--^
var i=1,j=++i;  //i和j的值都是2
var i=1,j=i++;  //i是2,j是1

数学常量

Math.EMath.LN10Math.LN2Math.LOG10EMath.LOG2EMath.PIMath.SQRT1_2Math.SQRT2

数学函数

Math.abs(x)xMath.acos(x)xMath.asin(x)xMath.atan(x)xMath.atan2(y,x)yxMath.ceil(x)xMath.cos(x)xMath.exp(x)xMath.floor(x)xMath.log(x)xMath.max(args…)Math.min(args…)Math.pow(x,y)xyMath.random()Math.round(x)xMath.sin(x)xMath.sqrt(x)xMath.tan(x)x

数字相关方法

n.toExponential(digits)ndigitsn.toFixed(digits)ndigitsn.toLocaleString()nn.toPrecision(prec)precprectoFixedprec-1n.toString()nNumber(object)DateNumber()Number()NaN

字符串

由单引号或双引号括起来的字符序列。由单引号定界的字符串中可以包含双引号,由双引号定界的字符串中也可以包含单引号。

'can't'
+
var msg="hello, "+"world";   //生成字符串“hello, world”
lengthmsg.length
><
"aBc""ab"
localeCompare
0930394857AZ415A6590az617A97122一龥4E009FA51996840869

字符串相关方法

s.charAt(n)sns.concat(value,…)s="hello"; s.concat("","world","!");s.indexOf(s1 [,start])sstarts1-1s.lastIndexOf(s1[,start])s1sstart-1ss.trim()s.match(s1)s1nulls.replace(s1,s2)ss2s1s1-1s.slice(start,end)startends.split(delimiter)delimiterss.substr(start,length)startlengths.substring(start,end)startends.toLocaleLowerCase()ss.toLocaleUpperCase()ss.toLowerCase()ss.toUpperCase()ss.localeCompare(s1[,locale])ss1ss10"张三""李四"s.localeCompare(s1,"zh")locale
nullundefined
truefalse
&&||!
==<><=>=!=
null
undefinedundefined

变量

var
var i,j;        //通过一个var声明多个变量
var i=0,j=0;    //可以将变量的初始赋值和变量声明合写在一起

变量的作用域:

var scope="global";
function f() {
    console.log(scope);     //输出“undefined”,而不是“global”
    var scope="local";      //变量在这里赋初始值,但变量本身在函数体内任何地方均是有定义的
    console.log(scope);     //输出“local”
    }

赋值

=

带操作的赋值运算:

+=a+=ba=a+b-=a-=ba=a-b*=a*=ba=a*b/=a/=ba=a/b%=a%=ba=a%b^=a^=ba=a^b

语句

条件语句

通过判断指定表达式的值来决定执行还是跳过某些语句。JavaScript中基本的条件语句有2种:

// 1
if (条件)
  语句1;
[else
 语句2;]
//2
if (条件){
    语句块1;
    }
[else{
    语句块2;
    }]
  
  
  
      
      chap3-1
      
  
  
The Grade:
switch (expression){
    case e1:    //如果expression==e1,则执行语句块1
        语句块1;
        break;  //停止执行switch语句
    case e2:    //如果expression==e2,则执行语句块2
        语句块2;
        break;
    case en:    //如果expression==en,则执行语句块n
        语句块n;
        break;
    default:    //如果所有的条件都不匹配,则执行语句块n+1
        语句块n+1;
        break;
        }
The Grade:

循环语句

可以让一部分代码重复执行。JavaScript中有4种循环语句:

// 1
while (条件)
    语句;
// 2
while (条件){
    语句块;
    }

阶乘:
// 1
do
    语句;
    while(条件);
// 2
do{
    语句块;
    }while(条件);

阶乘:
for(initialize;test;increment){
    statements;
    }

阶乘:
for(variable in object){
    statements;
    }

跳转语句

可以使得JavaScript的执行从一个位置跳转到另一个位置。

breakcontinue

chap3-7.html


标签语句

identifier:statement
breakcontinue
break|continue identifier;
mainloop: while(j<=100){
    j++;
    continue mainloop;  //跳转到下一次循环
    }
alert("j的值为:"+j);
mainloop: while(j<=100){
    j++;
    break mainloop;
    }
alert("j的值为:"+j);   //break语句跳转至此处
continue
return
return expression;
function squre(x) {
    return x*x;
    }
document.writeln("2的平方等于:"+squre(2)+"
");

异常处理语句

所谓异常(exception)是当发生了某种异常情况或错误时产生的一个信号。抛出异常就是用信号通知发生了错误或异常情况。捕获异常是指处理这个信号,即采取必要的手段从异常中恢复。

throwthrow expression;
trycatchfinally
try{
    //通常来讲,这里的代码会从头执行到尾而不会产生问题,但有时会抛出一个异常,要么是由throw语句直接抛出异常,要么是通过调用一个方法间接抛出异常
    }
catch(e){
    //当且仅当try语句块抛出了异常,才会执行这里的代码。这里可以通过局部变量e来获得对Error对象或者抛出的其它值的引用,这里的代码块可以基于某种原因处理这个异常,也可以忽略这个异常,还可以通过throw语句重新抛出异常。
    }
finally{
    /*不管try语句块是否抛出了异常,这里的逻辑总是会执行,终止try语句块的方式有:
    1)正常终止,执行完语句块的最后一条语句
    2)通过break、continue或return语句终止
    3)抛出一个异常,异常被catch从句捕获
    4)抛出一个异常,异常未被捕获,继续向上传播
    */
    }

chap3-8.html


数组

数组是值的有序集合。每个值叫做一个元素,而每个元素在数组中有一个位置,以数字表示,称为索引。

JavaScript数组是无类型的:数组元素可以是任意类型,并且同一个数组中的不同元素也可能有不同的类型。

创建

创建数组有2种方式:

var empty=[];   //没有元素的数组
var primes=[1,2,3,4,5];     //有5个数值的数组
var misc=[1.1,true,"a"];    //3个不同类型的元素
var base=1024;
var table=[base,base+1,base+2];     //值可以是表达式
var b=[{x:1,y:2},primes];   //值还可以对象或其它数组
var count=[1,,3];   //数组有3个元素,中间的那个元素值为undefined
var undefs=[,,];    //数组有2个元素,都是undefined
var a=new Array(5,4,"testing");

读写

[]
var a=["hello"];    //从一个元素的数组开始
var value=a[0];     //读第0个元素
a[1]=3.14;          //写第1个元素
i=2;
a[i]=3;             //写第2个元素
document.write(a.length);
length123
undefined

稀疏数组

lengthArray()
a=new Array(5);     //数组没有元素,但是a.length是5
a[1000]=0;      //赋值添加一个元素,但是设置length为1001

足够稀疏的数组通常在实现上比稠密的数组更慢,内存利用率更高,在这样的数组中查找元素的时间更长。

元素的添加

数组元素的添加有3种方式:

var a=[];   //开始是一个空数组
a[0]="zero";    //然后向其中添加元素
a[1]="one";
var a=[];   //开始是一个空数组
a.push("zero");    //在末尾添加一个元素
a.push("one","two");    //在末尾添加两个元素
var a=[];   //开始是一个空数组
a.unshift("two");    //在头部添加一个元素
a.unshift("zero","one");    //在头部添加两个元素

元素的删除

数组元素的删除有3种方式:

var a=[1,2,3];
delete a[1];    //a在索引1的位置不再有元素
var a=[1,2,3];
a.pop();    //删除a尾部的元素
var a=[1,2,3];
a.shift();    //删除a头部的元素

多维数组

JavaScript不支持真正的多维数组,但可以用数组的数组来近似。

chap3-9.html






数组方法

join()
var a=[1,2,3];  //创建一个包含三个元素的数组
var str=a.join();   //str的值为“1,2,3”
str=a.join(" ");    //str的值为“1 2 3”
reverse()
var a=[1,2,3];  //创建一个包含三个元素的数组
a.reverse();
for(var i=0;i"),i++);
sort()arrayObject.sort([sortby])
var a=["banana","cherry","apple"];
a.sort();
for(var i=0;i"),i++);
var b=[33,4,1111,222];
b.sort();   //输出结果:1111 222 33 4
for(var i=0;i"),i++);

chap3-10.html


concat()concat()concat()
concat()concat()

chap3-11.html


    
    chap3-11
    
    



slice()
arrayObject.slice(start,end)
start-1-2endstart
var a=[1,2,3,4,5];
document.write(a.slice(0,3)+"
"); //返回[1,2,3] document.write(a.slice(3)+"
"); //返回[4,5] document.write(a.slice(1,-1)+"
"); //返回[2,3,4]
splice()
arrayObject.splice(index,howmany,item1,.....,itemX)
indexhowmany0item1itemXsplice()indexarrayObject

chap3-12.html


函数

函数是这样的一段JavaScript代码,它只定义一次,但可能被执行或调用任意次。

JavaScript函数是参数化的:函数的定义会包括一个称为形参(parameter)的标识符列表,这些参数在函数体中像局部变量一样工作。函数调用会为形参提供实参(argument)的值。函数使用它们实参的值来计算返回值,成为该函数调用表达式的值。

this

JavaScript的函数可以嵌套在其他函数中定义,这样就构成了一个闭包(closure)。

定义

function
function jc(x) {
    var result=1;
    for(var i=1;i<=x;i++){
        result*=i;
    }
    return result;
    }
var a=Number(prompt("请输入一个正整数:",""));
document.write(jc(a)+"
");
var square=function(x) {return x*x;};   //定义时函数名称省略
document.write(square(a)+"
"); //调用时使用变量名称(实参)形式 var f=function fact(x) { //定义时可以包含函数名称 if (x<=1) return 1; else return x*fact(x-1); } document.write(f(a)+"
"); //调用时使用变量名称(实参)形式

如同变量,函数声明语句“被提前”到外部脚本或外部函数作用域的顶部,所以以这种方式声明的函数,可以被在它定义之前出现的代码所调用。

但是,对于函数定义表达式而言,就另当别论了,为了调用一个函数,必须要能引用它,而要使用一个以表达式方式定义的函数之前,必须把它赋值给一个变量。变量的声明提前了,但给变量赋值是不会提前的,所以,以表达式方式定义的函数在定义之前无法调用。

chap3-13.html


调用

有4种方式来调用JavaScript函数:

var name="zhangsan";
var obj={
    name:"lizi",
    getName:function () {
        document.write(this.name + "
"); } } obj.getName(); //输出lizi
var name="zhangsan";
var obj={
    name:"lizi",
    getName:function () {
        document.write(this.name + "
"); } } var nameGet=obj.getName; nameGet(); //输出zhangsan
var name="zhangsan";
var obj1=function (x,y) {
    this.name=x+y;
    }
obj1.prototype.getName=function () {
    document.write(this.name + "
"); } var myObj=new obj1("wang","er"); myObj.getName(); //输出wanger
function Sister() {
    this.age=18;
    this.sayAge=function () {document.write("Age:"+this.age+ "
");} } function Brother() { this.age=25; this.sayAge=function () {document.write("Age:"+this.age+ "
");} } var sis=new Sister(); var bro=new Brother(); sis.sayAge.call(bro); //输出"Age:25"
window.firstName="San";
window.lastName="Zhang";
var myObject={firstName:"my",lastName:"Object"};
function HelloName() {document.write(this.firstName+" "+this.lastName+ "
");} HelloName.call(window); //输出"San Zhang" HelloName.call(this); //输出"San Zhang" HelloName.call(myObject); //输出"my Object" function sum(m,n) { return m+n; } document.write(sum.call(window,10,10)+ "
"); //输出20 document.write(sum.apply(window,[10,20])+ "
"); ////输出30

实参和形参

JavaScript中的函数定义并未指定函数形参的类型,函数调用也未对传入的实参值做任何类型检查。实际上,JavaScript函数调用甚至不检查传入形参的个数。

undefined
  • 注意:当用这种可选形参来实现函数时,需要将可选形参放在形参列表的最后。

chap3-15.js

function int(x,type) {
    if(type===undefined) return Math.floor(x);
    if(type===1) return Math.floor(x);
    if(type===2) return Math.ceil(x);
    if(type===3) return Math.round(x);
    }
document.write("3.4默认去尾法取整:" +int(3.4)+"
"); document.write("3.4去尾法取整:" +int(3.4,1)+"
"); document.write("3.4进位法取整:" +int(3.4,2)+"
"); document.write("3.4四舍五入取整:" +int(3.4,3)+"
");

可变长的实参列表(实参对象):当调用函数的时候传入的实参个数超过函数定义时的形参个数时,没有办法直接获得未命名值的引用。参数对象解决了这个问题。

fxfxarguments[0]arguments[1]arguments.lengthargumentslength

chap3-15.js

function max() {
    var max=Number.NEGATIVE_INFINITY;   //NEGATIVE_INFINITY 表示负无穷大
    for(var i=0;imax) max=arguments[i];
    }
    return max;
    }
var largest=max(1,10,100,2,3,1000,4,5,10000,6);
document.write("最大值为:"+largest+"
");

将对象属性用做实参:当一个函数包含超过三个形参时,对于程序员来说,要记住调用函数中实参的正确顺序很难。最好通过名/值对的形式来传入参数,这样参数的顺序就无关紧要了。为了实现这种风格的方法调用,定义函数时,传入的实参都写入一个单独的对象中,在调用的时候传入一个对象,对象中的名/值对是真正需要的实参数据。

chap3-15.js

function arraycopy(from,from_start,to,to_start,length) {
    for(var i=to_start;i");}

作为值的函数

在JavaScript中,函数不仅是一种语法,也是值,也就是说,可以将函数赋值给变量。

chap3-16.js

function squre(x) {return x*x;}
var s=squre;    //现在s和squre指代同一个函数
document.write(squre(4)+"
"); document.write(s(4)+"
");

除了可以将函数赋值给变量,同样可以将函数赋值给对象的属性。

chap3-16.js

var o={square:squre};
var x=o.square(16);
document.write(x+"
");

函数甚至不需要带名字,当把它们赋值给数组元素时:

chap3-16.js

var a=[function (x) {return x*x},20];
document.write(a[0](a[1])+"
");

作为命名空间的函数

JavaScript中变量的作用域有全局变量和局部变量2种。在JavaScript中是无法声明只在一个代码块内可见的变量的,基于这个原因,我们常常简单地定义一个函数用做临时的命名空间,在这个命名空间内定义的变量都不会污染到全局命名空间。

function mymodule() {
    //模块代码,这个模块所使用的所有变量都是局部变量,而不是污染全局命名空间
    }
mymodule();     //不要忘了还要调用这个函数
mymodule
(function () {
  //模块代码
}());   //结束函数定义并立即调用它

闭包

出于种种原因,我们有时候需要得到函数内的局部变量。闭包可以捕捉到局部变量(和参数),并一直保存下来。闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!

chap3-17.js

var scope="global scope";       //全局变量
function checkscope() {
    var scope="local scope";    //局部变量
    function f() {return scope;}    //在作用域中返回这个值
    return f();
    }
var a=checkscope();
document.write(a+"
")

对象

对象是一种复合值,它将很多值聚合在一起,可通过名字访问这些值。对象也可看作是属性的无序集合,每个属性都是一个名/值对。属性名是字符串,因此我们可以把对象看成是从字符串到值的映射。

对象除了可以保持自有的属性外,还可以从一个称为“原型”的对象继承属性。

truefalsenullundefined

除了包含属性之外,每个对象还拥有三个相关的对象特性:

对象的原型(prototype)指向另一个对象,本对象的属性继承自它的原型对象。

对象的类(class)是一个标识对象类型的字符串。

对象的扩展标记(extensible flag)指明了(在ECMAScript 5中)是否可以向该对象添加新属性。

JavaScript对象的类别

HTMLElement

创建对象

创建对象(3种方式):

var empty={};    //空对象,没有任何属性
var point={x:0,y:0};    //两个属性
var book={
    "main title":"JavaScript",      //属性名字里有空格,必须用字符串表示
    "sub-title":"The Definitive Guide",     //属性名字里有连字符,必须用字符串表示
    "for":"all audiences",      //"for"是保留字,因此必须用引号
    author:{            //这个属性的值是一个对象
        firstname:"Shulin",
        lastname:"Chen"
    }
};
var author=new Object(); //创建一个空对象
author.firstname="Shulin";
author.lastname="Chen";
var mycars=new Array();
mycars[0]="Saab";
mycars[1]="Volvo";
var today = new Date();  //Date 对象自动使用当前的日期和时间作为其初始值。
var o1 = Object.create({x:1,y:2});  //o1继承了属性x和y
var o2 = Object.create(Object.prototype);   //o2和{}以及new Object()一样,创建了一个普通的空对象
//inherit()返回了一个继承自原型对象p的属性的新对象
//这里使用ECMAScript 5中的Object.create()函数(如果存在的话)
//如果不存在Object.create(),则退化使用其它方法
function inherit(p) {
    if(p==null) throw TypeError();      //p是一个对象,但不能是null
    if(Object.create) return Object.create(p);      //如果Object.create()存在,直接使用它
    var t=typeof p;
    if(t!=="object" && t!=="function") throw TypeError();
    function f() {};    //定义一个空构造函数
    f.prototype=p;      //将其原型属性设置为p
    return new f();     //使用f()创建p的继承对象
    }
//Inherit()函数的其中一个用途就是防止函数无意间(非恶意地)修改那些不受你控制的对象。
// 不是将对象直接作为参数传入函数,而是将它的继承对象传入函数。
//如果给继承对象的属性赋值,则这些属性只会影响这个继承对象自身,而不是原始对象。
var o={x:"don't change this value"};
changex(inherit(o));
function changex(obj) {
    obj.x="hello world!";
    document.write(obj.x+"
"); } document.write(o.x+"
"); changex(o); document.write(o.x+"
");

属性的查询和设置

JavaScript为属性访问定义了两种语法:

对象名.属性名对象名[表达式]
表达式
.book.forbook["for"]
[]

chap3-19.html


JavaScript对象具有自有属性(实例属性),也有一些属性是从原型对象继承而来的(继承属性)。

qxqxqxxxnull

chap3-20.html


    
    chap3-20
    
    



oxoxxoxoxox
ox

chap3-20.js

var a={
    get r(){return 1;},
    x:1
    };
var b=inherit(a);   //b继承属性r
b.y=1;              //b定义了个属性
b.x=2;              //b覆盖继承来的属性x
b.r=3;              //r为只读属性,赋值语句无效
document.write(b.r+"
"); //输出1 document.write(b.x+"
"); //输出2 document.write(a.x+"
"); //原型对象没有修改

删除属性

delete
delete
delete

chap3-21.js

var book={
    "main title":"JavaScript",
    "sub-title":"The Definitive Guide",
    "for":"all audiences",
    author:{
        firstname:"Shulin",
        lastname:"Chen"
    }
    };
delete book.author;     //book不再有属性author
delete book["main title"];  //book不再有属性"main title"
document.write(book.author+"
"); document.write(book["main title"]+"
"); var o=Object.create(book); //o继承了book对象的属性 delete o["for"]; //不能删除继承属性 document.write(book["for"]+"
");

检测属性

判断某个属性是否存在于某个对象中可以有3种方式:

intrue
hasOwnProperty()truefalse
propertyIsEnumerable()truetrue
var o={x:1};
var obj=Object.create(o);
obj.y=2;
"x" in obj;  //输出true
"y" in obj;  //输出true
obj.hasOwnProperty("x");  //输出false
obj.hasOwnProperty("y");  //输出true
obj.propertyIsEnumerable("x");   //输出false
obj.propertyIsEnumerable("y");  //输出true

枚举属性

enumerable
ObjectArrayNumber
ObjectpropertyIsEnumerable()
forin
Object.keys()
Object.getOwnPropertyNames()

chap3-22.js

var po={px:1,py:2};
var o={x:3,y:4};
o.__proto__=po;     //设置o的原型为po
document.write("for/in方法输出结果:
"); for(property in o){ document.write(property+":"+o[property]+"
"); } var propertyArray=Object.keys(o); document.write("定义枚举属性前Object.keys方法输出结果:
"); for(var i=0;i"); } Object.defineProperties(o,{ x:{enumerable:true}, y:{enumerable:false} }); propertyArray=Object.keys(o); document.write("定义枚举属性后Object.keys方法输出结果:
"); for(var i=0;i"); } propertyArray=Object.getOwnPropertyNames(o); document.write("定义枚举属性后Object.getOwnPropertyNames方法输出结果:
"); for(var i=0;i"); }
gettersetter
attributegettersettergettersetter

数据属性:包含属性的操作特性;如:设置值、是否可枚举等。

valueundefinedwritabletruefalsefalseenumerabletrueforinfalsefalseconfigurabletruewritablefalsetruefalsefalse

存取器属性:包含属性的操作特性;如:设置值、是否可枚举等。

getundefinedsetundefinedenumerabletrueforinfalsefalseconfigurabletruewritablefalsetruefalsefalse

存取器也是可以继承的。

chap3-23.html


属性的特性

为了实现属性特性的查询和设置操作,ECMAScript 5中定义了一个名为“属性描述符”(property descriptor)的对象,这个对象代表数据属性特性和存取器属性特性。

Object.definePropertyObject.definePropertiesObject.createwritableenumerableconfigurablefalse
writableenumerableconfigurabletrue
Object.getOwnPropertyDescriptor(object,propertyname)objectpropertyname

chap3-24.html




    
    chap3-24
    




三个属性

原型属性

是用来继承属性的,指向另一个对象,本对象的属性继承自它的原型对象。

Object.prototypenewprototypeObject.create()
Object.getPrototypeOf()
isPrototypeOf()
var p={x:1,y:2};
var o=Object.create(p);
document.write(p.isPrototypeOf(o)+"
"); //返回true document.write(Object.prototype.isPrototypeOf(o)); //返回true
类属性
toString()[object class]
toStringFunction.call()

chap3-25.html


可扩展属性

用以表示是否可以给对象添加新属性。所有内置对象和自定义对象都是显式可扩展的。

Object.isExtensible()
Object.preventExtensions()

类和模块

在JavaScript中也可以定义对象的类,让每个对象都共享某些属性,这种"共享"的特性是非常有用的。类的成员或实例都包含一些属性,用以存放它们的状态,其中有些属性定义了它们的行为(通常称为方法)。这些行为通常是由类定义的,而且为所有实例所共享。

在JavaScript中,类的实现是基于其原型继承机制的。如果两个实例都从一个原型对象上继承了属性,我们说它们是同一个类的实例。

JavaScript中类的一个重要特征是"动态可继承"(dynamically extendable),定义类是模块开发和重用代码的有效方式之一。

类和原型

在JavaScript中,类的所有实例对象都从一个类型对象上继承属性。因此,原型对象是类的核心。

inherit()inherit()

chap3-26.html



range()range()range.methodsrange()fromtorange.methodsfromtothisthisthis

类和构造函数

newprototype

chap3-27.html


一个常见的编程约定:从某种意义上来讲,定义构造函数即是定义类,并且类首字母要大写,而普通的函数和方法首字母都是小写。

Range()new
range.methodsRange.prototypeRange()Range.prototypeRange

构造函数和类的标识

原型对象是类的唯一标识:当且仅当两个对象继承自同一个原型对象时,它们才是属于同一个类的实例。而初始化对象的状态的构造函数则不能作为类的标识,两个构造函数的prototype属性可能指向同一个原型对象。那么这两个构造函数创建的实例是属于一个类的。

Range()RangeinstanceofrrRange
r instanceof Range // 如果r继承自Rang.prototype,则返回true 
prototypeprototypeconstructorconstructor
var F = function() {}; //这是一个函数对象:
var p = F.prototype; //这是F相关联的原型对象
var c = p.constructor; //这是与原型相关的函数
c === F; //=>true  对于任意函数F.prototype.constructor == F

下图展示了构造函数和原型之间的关系,包括原型到构造函数的反向引用及构造函数创建的实例。

RangeprototypeconstructorRange()Object.prototype.constructorObject()

Chap3-28.html

Range.prototype = {
    constructor:Range,  //显式的设置构造函数反向引用
    includes: function(x) {
        return this.from <= x && x <= this.to;
    },
    //对于这个范围内的每个整数都调用一次f
    //这个方法只可用于数字范围
    foreach: function(f) {
        for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
    },
    //返回表示这个范围的字符串
    toString: function() {
        return "(" + this.from + "..." + this.to + ")";
    }
};
constructor

Chap3-29.html

//扩展预定义的Range.prototype对象,而不重写之
//这样就自动创建Range.prototype.constructor属性
Range.prototype.includes=function(x){
    return this.from <= x && x <= this.to;
};
//对于这个范围内的每个整数都调用一次f
//这个方法只可用于数字范围
Range.prototype.foreach = function(f) {
    for (var x = Math.ceil(this.from); x <= this.to; x++) f(x);
};
//返回表示这个范围的字符串
Range.prototype.toString=function() {
    return "(" + this.from + "..." + this.to + ")";
};

在JavaScript中定义类的步奏可以缩减为一个分三步的算法。

prototype

Complex.js

/*这个文件定义了Complex类,用来描述复数。这个构造函数为它所创建的每个实例定义了实例字段r和i,分别保存复数的实部和虚部*/
function Complex(real, imaginary) {
    this.r = real;                       // The real part of the complex number.
    this.i = imaginary;                  // The imaginary part of the number.
}
/*类的实例方法定义为原型对象的函数值的属性
*这个库定义的方法可以被所有实例继承,并为它们提供共享的行为
*需要注意的是,javascript的实例方法必须使用关键字this才存取实例的字段*/
Complex.prototype.add = function(that) {
    return new Complex(this.r + that.r, this.i + that.i);
};
Complex.prototype.equals = function(that) {
    return that != null &&                      // must be defined and non-null
        that.constructor === Complex &&         // and an instance of Complex
        this.r === that.r && this.i === that.i; // and have the same values.
};
Complex.prototype.toString = function() {
    return "{" + this.r + "," + this.i + "}";
};
//类字段(比如常量)和类方法直接定义为构造函数的属性
//这里定义了一些对复数运算有帮助的类的字段,它们的命名全都是大写,用以表明它们是常量
Complex.ZERO = new Complex(0,0);
Complex.I = new Complex(0,1);

Chap3-30.htnl




    
    chap3-30
    





类的扩充

JavaScript中基于原型的继承机制是动态的:对象从其原型继承属性,如果创建对象之后原型的属性发生改变,也会影响到继承这个原型的所有实例对象。这意味着我们可以通过给原型对象添加新的方法来扩充JavaScript类。

Chap3-31.html




    
    chap3-31
    





正则表达式的模式匹配

RegExpRegExp()RegExpRegExp/
var pattern=/s$/;   //用来匹配所有以字母“s”结尾的字符串
RegExp()
var pattern1=new RegExp("s$");
/java/

直接量字符

javascript正则表达式中的直接量字符:

ou0000	u0009
u000Au000Bu000C
u000Dxnn

uxxxxxxxxu0009	

字符类

/[abc]/
[...][^...].w[a-zA-Z0-9]W[^a-zA-Z0-9]sSd[0-9]D[^0-9]
sd/[sd]/

Chap3-32.html




    
    chap3-32
    


重复

{n,m}{n,}{n}?{0,1}+{1,}*{0,}
/d{2,4}/        //匹配2~4个数字 
/w{3}d?/       //精确匹配三个单词和一个可选的数字 
/s+javas+/    //匹配前后带一个或多个空格的字符串“java” 
/[^(]*/         //匹配1个或多个非左括号的字符 
*?/a*/

Chap3-33.html




    
    chap3-33
    


非贪婪的重复

上表中匹配重复字符是尽可能多地匹配,而且允许后继的正则表达式继续匹配。因此,我们称之为“贪婪的”匹配。

??+?*?{1,5}?/a+//a+?/
/a+b//a+?b/

选择、分组和引用

正则表达式的语法还包括指定选择项、子表达式分组和引用前一子表达式的特殊字符。

(...)*+?(?:...)
(?:
|
/ab|cd|ef/      //可以匹配字符串"ab",也可以匹配字符串"cd",还可以匹配字符串"ef"
/d{3}|[a-z]{4}/   //可以匹配三位数字或4个小写字母
/a|ab/

正则表达式中的圆括号有多种作用。

|*+?
/java(script)?/     //可以匹配字符串"java",其后可以有"script"也可以没有
/(ab|cd)+|ef/       //可以匹配字符串"ef",也可以匹配字符串"ab"或"cd"的一次或多次重复

Chap3-34.html


/([Jj]ava([Ss]cript)?)siss(funw*)/       //嵌套的子表达式([Ss]cript)可以用来指代

注意:因为子表达式可以嵌套另一个子表达式,所以它的位置是参与计数的左括号的位置。

/['"][^'"]*['"]/       //匹配的就是位于单引号或双引号之内的0个或多个字符。
/(['"])[^'"]*/        //与上面的正则表达式等价
(?:...)
//这种改进的圆括号并不生成引用。所以在这个表达式中,引用了与(funW*)匹配的文本。
/([Jj]ava(?:[Ss]cript)?)siss(funw*)/

指定匹配位置

正则表达式中的锚字符:

^$wWw[]B(?=p)pp(?!p)p
^$
/^JavaScript$/       //要匹配单词“JavaScript”
/sJavas/s/Java/
B/B[Ss]cript/
(?=)/[Jj]ava([Ss]cript)?(?=:)/
(?!/Java(?!Script)([A-Z]w*)/

Chap3-35.html



修饰符

/
igm^$
/java$/im   //可以匹配java,也可以匹配"Java
is Fun".
String

String支持4种使用正则表达式的方法:

document.write("javascript".search(/script/i));     //返回4
var text="javascript and Javascript and javascript";
document.write(text.replace(/javascript/gi,"JavaScript"));
text="1 plus 2 equals 3";
var arr=text.match(/d+/g);
text="1, 2, 3, 4, 5";
var arr=text.split(/s*,S*/);  //允许两边可以留任意多的空白符
RegExp
RegExpRegExp()
//全局匹配字符串中的6个数字,注意这里使用了"\",而不是“”
var zipcode=new RegExp("\d{6}","g");
RegExp
sourceglobalgignoreCaseimultilinemlastIndexgexec()test()

Chap3-36.html


RegExp
exec()
RegExpObject.exec(string)
exec()nullRegExpObjectRegExpObjectRegExpexec()String.match()RegExpObjectRegExpObjectlastIndexstringexec()RegExpObjectlastIndexexec()exec()nulllastIndex
test()
RegExpObject.test(string) 
stringRegExpObjecttruefalse

Chap3-37.html




    
    chap3-37





客户端JavaScript

  • document对象

  • Window对象

  • 使用DOM元素

  • 脚本化CSS

  • 脚本化HTTP

  • jQuery类库

  • 客户端存储

  • JSON

document对象

文档对象模型DOM把JavaScript和HTML文档的内容联系起来。通过使用DOM,可以添加、移除和操作各种元素,还可以使用事件(event)来响应用户的交互操作,以及完全控制CSS。

document对象是通往DOM功能的入口,它向你提供了当前文档的信息,以及一组可供探索、导航、搜索或操作结构与内容的功能。

documentdocument.locationdocument.cookiedocument.readystatedocument.implementationdocumentimageslinksdocument.getElementdocument.querySelectordocument.querySelectorAllhasChildNodes()
document
characterSetcharsetcompatModecookiedefaultCharsetdirdomainimplementationlastModifiedlocationreadyStatereferrertitle

Chap3-38.html


    
    chap3-38
    



compatMode属性返回值有两个:

CSS1CompatBackCompat

使用Location对象

protocolhosthrefhostnameportpathnamesearchhashassign(URL)replace(URL)reload()resolveURL(URL)

Chap3-39.html





读取和写入cookie

name=value

在创建cookie时,可以添加额外字段来改变cookie的处理方式:

path=pathdomain=domainmax-age=secondsexpires=datesecure

Chap3-40.html

readyState
document.readyStatescriptdefer
readyStateloadinginteractivecomplete

Chap3-41.html




    
    chap3-41




使用属性获取HTML元素对象

bodyembedformheadimghrefaareascript

Chap3-42.html

namedItemidname




I like apples

I love sun

搜索元素

getElementById(id)idgetElementsByClassName(class)classgetElementsByName(name)namegetElementsByTagName(tag)querySelector(selector)querySelectorAll(selector)

Chap3-43.html

pidappleimg


I like apples

I love sun

合并进行链式搜索

HTMLElementgetElementById

Chap3-44.html



I like apples and bananas I love sun

在DOM树里导航

另一种搜索元素的方法是将DOM视为一棵树,然后在它的层级结构里导航。

navigationchildNodesfirstChildhasChildNodes()truelastChildnextSiblingparentNodepreviousSibling

Chap3-45.html


    
    chap3-45
    


I like apples and bananas

I love sun

Window对象

document.defaultViewwindowwindowalertconfimpromptshowModalDialogWindow.historyHistorybackforwardgoWindow.historyHistorypushStatereplaceStatesetIntervalsetTimeoutclearIntervalclearTimeout

获取Window对象

可以用两种方式获得Window对象:

defaultViewwindow

Chap3-46.html


    
    chap3-46
    


outerWidth:
outerHeight:

获取窗口信息

innerHeightinnerWidthouterHeightouterWidthpageXOffsetpageYOffsetscreenscreenLeftscreenTop

Chap3-46.html


outerWidth:
outerHeight:
innerWidth:
innerHeight:
screenWidth:
screenHeight:
screenLeft:
screenTop:
screen
screenavailHeightavailWidthcolorDepthheightwidth

与窗口进行交互

Window对象提供了一组方法,可以用它们与包含文档的窗口进行交互。

blur()close()focus()print()scrollBy(x,y)scrollTo(x,y)stop()

Chap3-47.html



In ecology, primary compounds as … Gross primary production (GPP) is….

对用户进行提示

Window对象包含一组方法,能以不同的方式对用户进行提示。

alert(msg)confirm(msg)prompt(msg,val)showModalDialog(url)
showModalDialog

Chap3-48.html








使用浏览器历史

Window.history
back()forward()go(index)length

Chap3-49.html







使用计时器

Window对象提供的计时方法有:

clearInterval(id)clearTimeout(id)setInterval(function,time)timesetTimeout(function,time)time
setTimeoutsetIntervalclearIntervalclearTimeout

Chap3-50.html


使用DOM元素

classNameclassListattributegetAttributesetAttributeremoveAttributehasAttributedatasetTextdocument.createcloneNodeappendChildisSameNodeisEqualNodeinnerHTMLouterHTMLinsertAdjacentHTMLsplitTextappendChild

使用元素对象

HTMLElement对象提供了一组属性,可以用来读取和修改被代表元素的数据。

checkedididclassListlanglangclassNamespellcheckspellcheckdirdirtabIndextabIndexdisableddisabledtagNamehiddenhiddentitletitle

Char3-57.html



I like apples and banana.




可以用两种方法处理某个元素所属的类:

classNameclassList
add(class)contains(class)truelengthremove(class)toggle(class)

Char3-57.html





I like apples and banana.








使用元素属性

attributesdatasetdata-getAttribute(name)hasAttribute(name)trueremoveAttribute(name)setAttribute(name,value)

Chap3-58.html



I like apples and banana.




使用Text对象

元素的文本内容是由Text对象代表的,它在文档模型里表现为元素的子对象。当浏览器在文档模型里生成p元素时,元素自身会有一个HTMLElement对象,内容则会有一个Text对象。

I like apples and banana.

appendData(string)datadeleteData(offset,count)insertData(offset,stringlengthreplaceData(offset,count,string)replaceWholeText(string)splitText(number)substringData(offset,count)wholeText

Chap3-59.html


I like apples and banana.





修改DOM

appendChild(HTMLElement)cloneNode(boolean)compareDocumentPosition(HTMLElement)innerHTMLinsertAdjacentHTML(pos,text)insertBefore(newElem,childElem)isEqualNode(HTMLElement)isSameNode(HTMLElement)outerHTMLremoveChild(HTMLElement)replaceChild(HTMLElement, HTMLElement)createElement(tag)createTextNode(text)

Chap3-60.html


    
    chap3-60
    


NameColor
BananaYellow
AppleRed

脚本化CSS

行间样式

脚本化CSS就是使用javascript来操作CSS。引入CSS有3种方式:行间样式、外部样式和内部样式。

行间样式又叫内联样式,使用HTML的style属性进行设置:

stylestyle
test.style.height = '30px'; 

如果一个CSS属性名包含一个或多个连字符,CSSStyleDeclaration属性名的格式应该是移除连字符,将每个连字符后面紧接着的字母大写:

console.log(test.style.backgroundColor)
hello world

var divResults=document.getElementById("results");
divResults.innerHTML=divTest.style.length;
var resFontsize=divTest.style.item(0);
divResults.innerHTML=resFontsize+":"+divTest.style.getPropertyValue(resFontsize);
divResults.innerHTML=divResults.style.getPropertyPriority("height");
divResults.style.setProperty('height','20px','important');
divResults.style.removeProperty('background-color');

Chap3-51.html


hello world

查询计算样式

元素的渲染结果是多个CSS样式博弈后的最终结果,浏览器会从多个来源汇聚样式以计算出该用哪个值来显示某一元素。浏览器用于显示某个元素的CSS属性值集合被称为计算样式。

getComputedStyle()
document.defaultView.getComputedStyle(element[,pseudo-element]) 
//或
window.getComputedStyle(element[,pseudo-element])
//或
getComputedStyle(element[,pseudo-element])
getComputedStyle()nullgetComputedStyle()CSSStyleDeclaration

Chap3-52.html


hello world
getComputedStyle()
document.writeln(getComputedStyle(divTest).font);
document.writeln(getComputedStyle(divTest,":before").color);
#test:after{content: "!"; width: 1%; display: inline-block; color: blue;}
document.writeln(getComputedStyle(divTest,":after").width);
getComputedStyleelement.style

而不同点就是:

element.stylestylegetComputedStyleelement.styleelement.stylegetComputedStyle
getComputedStyleelement.style

脚本化CSS

在实际工作中,我们使用javascript操作CSS样式时,如果要改变大量样式,会使用脚本化CSS类的技术:

stylecssTextcssTextcssclassListclassList

hello world!
var divTest=document.getElementById("test");
divTest.onclick=function () {
        if(divTest.className=="big"){
            divTest.className="small";
        }else if(divTest.className=="small"){
            divTest.className="big";
        }
}

脚本化样式表

/pre>

pre>

document.styleSheets

/pre>

pre>

cssRulesdeleteRule(pos)disabledhrefhrefinsertRule(rule,pos)mediaownerNodetitletitletypetype

/pre>

h4>获得样式表的基本信息

/h4>

p>

Chap3-54.html

/p>

pre>

chap3-54

There are lots of different kinds of fruit

One of the most interesting aspects of fruit is the variety available in each country.

/pre>

p>

styles.css

/p>

pre>

a{ background-color: grey; color: white; } span{ border:thin black solid; padding: 10px; }

/pre>

h4>禁用样式表

/h4>

pre>

CSSStyleSheet.disabled

/pre>

p>

Chap3-55.html

/p>

pre>

There are lots of different kinds of fruit

/pre>

h4>CSSRuleList对象

/h4>

pre>

CSSStyleSheet.cssRules

/pre>

pre>

item(pos)length

/pre>

pre>

cssTextparentStyleSheetselectorTextstyle

/pre>

p>

Chap3-56.html

/p>

pre>

There are lots of different kinds of fruit

One of the most interesting aspects of fruit is the variety available in each country.

/pre>

h3>脚本化HTTP

/h3>

p>超文本传输协议(HyperText Transfer Protocol, HTTP)规定Web浏览器如何从Web服务器获取文档和向Web服务器提交表单内容,以及Web服务器如何响应这些请求和提交。

/p>

pre>

submit()

/pre>

p>Ajax描述了一种主要使用脚本操纵HTTP的Web应用架构。Ajax应用的主要特点是使用脚本操纵HTTP和Web服务器进行数据交换,不会导致页面重载。

/p>

p>Web应用可以使用Ajax技术把用户的交互数据记录到服务器中;也可以开始只显示简单页面,之后按需加载额外的数据和页面组件来提升应用的启动时间。

/p>

h4>Ajax起步

/h4>

p>Ajax的关键在于XMLHttpRequest对象。

/p>

p>第一步是创建一个新的XMLHttpRequest对象:

/p>

pre>

var httpRequest=new XMLHttpRequest();

/pre>

pre>

readystatechangeXMLHttpRequest.readyState

/pre>

pre>

UNSENT0OPENED1openHEADERS_RECEIVED2LOADING3DONE4

/pre>

pre>

open

/pre>

pre>

httpRequest.open(“GET”,“chap3-58.html”);

/pre>

pre>

send

/pre>

pre>

httpRequest.send();

/pre>

pre>

XMLHttpRequest.responseText

/pre>

pre>

document.getElementById("results").innerHTML=httpRequest.responseText;

/pre>

pre>

responseText

/pre>

p>

Chap3-61.html

/p>

pre>

Press a button

/pre>

h4>使用Ajax事件

/h4>

pre>

aborterrortimeoutreadystatechangeloadstartprogressloadloadend

/pre>

p>除了readystatechange之外,其他事件都定义于XMLHttpRequest规范的第二级。调度这些事件时,浏览器会对readystatechange事件使用常规的Event对象,对其他事件则使用ProgressEvent对象。

/p>

pre>

lengthComputabletrueloadedtotal

/pre>

p>

Chap3-62.html

/p>

pre>

Press a button

/pre>

h3>jQuery

/h3>

p>jQuery是一个JavaScript库,jQuery极大地简化了 JavaScript编程,jQuery很容易学习。jQuery 库包含以下特性:

/p>

ul>

  • HTML 元素选取和操作
  • CSS 操作
  • HTML 事件函数
  • JavaScript 特效和动画
  • HTML DOM 遍历和修改
  • AJAX
  • /ul>

    p>共有两个版本的jQuery可供下载:一份是精简过的,另一份是未压缩的(供调试或阅读)。这两个版本都可从jQuery.com下载。

    /p>

    p>:last$("p:last")

    /p>

    p>:even$("tr:even"):odd$("tr:odd"):eq(index)$("ul li:eq(3)")index:gt(no)$("ul li:gt(3)")index:lt(no)$("ul li:lt(3)")index:not(selector)$("input:not(:empty)")input:header$(":header")

    /p>

    code>:contains(text)$(":contains('W3School')"):empty$(":empty"):hidden$("p:hidden")

    /code>

    p>

    :visible$("table:visible")

    /p>

    input/>:text$(":text")type="text"

    input/>:password$(":password")type="password"

    input/>:radio$(":radio")type="radio"

    input/>:checkbox$(":checkbox")type="checkbox"

    input/>:submit$(":submit")type="submit"

    input/>:reset$(":reset")type="reset"

    input/>:button$(":button")type="button"

    input/>:image$(":image")type="image"

    input/>:file$(":file")type="file"

    input/>:enabled$(":enabled")input:disabled$(":disabled")input:selected$(":selected")input:checked$(":checked")input

    p>web存储

    /p>

    p>先是HTML5的一个API,后来成了标准了。目前包含IE8在内的主流浏览器都实现了。包含localStorage和sessionStorage对象,这两个对象实际上是持久化的关联数组,是名值对的映射表,“名”和“值”都是字符串。web存储易于使用,支持大容量(但非无限量)数据存储,同时兼容当前所有主流浏览器。

    /p>

    p>cookie

    /p>

    p>cookie是一种早期的客户端存储机制,起初是针对服务器端脚本设计使用的。尽管在客户端提供了非常繁琐的javascript API来操作cookie,但它们难用至极,而且只适合少量的文本存储。不仅如此,任何以cookie形式存储的数据,不论服务器端是否需要,每一次HTTP请求都要把这些数据传输到服务器端。cookie目前仍然被大量的客户端程序员使用的一个重要的原因是:所有新旧浏览器都支持它。但是,随着Web Storage的普及,cookie将最终回归到最初的形态:作为一种被服务端脚本使用的客户存储机制。

    /p>

    function>querystring.escape()querystring.parse(str[, sep[, eq[, options]]])querystring.stringify

    /function>

    Chap4-17.js

    var queryString=require("querystring");
    var str=queryString.escape("哈哈");
    console.log(str);  //%E5%93%88%E5%93%88
    console.log(queryString.unescape(str)); //哈哈
    console.log(queryString.stringify({ foo: 'bar', baz: ['qux', 'quux'], corge: '' }));
    // 返回 'foo=bar&baz=qux&baz=quux&corge='
    console.log(queryString.stringify({ foo: 'bar', baz: 'qux' }, ';', ':'));
    // 返回 'foo:bar;baz:qux'
    console.log(queryString.parse('name=pkcms&author=zh&date='));
    //{ name: 'pkcms', author: 'zh', date: '' }
    console.log(queryString.parse('name=pkcms&author=zh&author=hhy&date='));
    //相同的参数名会反序列化为一个数组,{ name: 'pkcms', author: [ 'zh', 'hhy' ], date: '' }
    console.log(queryString.parse('name=pkcms,author=zh,date=',','));
    //第2个参数是用来指明分隔符是用了哪个字符,{ name: 'pkcms', author: 'zh', date: '' }
    console.log(queryString.parse('name:pkcms,author:zh,date:',',',':'));
    //第3个参数是用来指明赋值符是用了哪个字符,{ name: 'pkcms', author: 'zh', date: '' }
    

    HTTP服务器与客户端

    httphttp.Serverhttp.request

    HTTP服务器

    http.ServerhttpHTTPhttp.Server
    http.ServerEventEmitter
    requestreqreshttp.ServerRequesthttp.ServerResponseconnectionnet.SocketconnectionrequestKeep-Aliveclose
    requesthttphttp.createServer([requestListener])requestListener

    Chap4-2.js

    var http=require('http')
    http.createServer(function (req,res) {
        res.writeHead(200,{"Content-Type":"text/html"});
        res.write("

    Node.js

    "); res.end("

    Hello World

    "); }).listen(3000);

    Chap4-15.js

    var http=require("http");
    var server=new http.Server();
    var count=0;
    server.on("connection",function () {
        console.log("someone connected!")
    });
    server.on("request",function (req,res) {
        res.writeHead(200,{"Content-Type":"text/html"});
        res.write("

    Node.js

    "); res.end("

    Hello World

    "); }); server.on("close",function () { console.log("server closed!") }); server.listen(3000); setTimeout(function () { server.close(); },5000); console.log("HTTP server is listening at port 3000.");
    http.ServerRequest
    http.ServerRequesthttp.Serverrequestrequestreq

    HTTP请求一般可以分为两部分:请求头(Request Header)和请求体(Requset Body)

    ServerRequestcompletehttpVersion1.01.1methodGETPOSTPUTDELETEurl/static/image/x.jpg/user?name=byvoidheaderstrailersconnectionnet.Socketsocketconnectionclientclient
    http.ServerRequest
    datachunkendcloseendclose
    获取 GET 请求内容
    ?urlparse
    var http=require("http");
    var url=require("url");
    http.createServer(function (req,res) {
       console.log(url.parse(req.url));
    }).listen(3000);
    
    http://localhost:3000/chap4-16?name=zhangsan&password=123456
    
    Url {
      protocol: null,
      slashes: null,
      auth: null,
      host: null,
      port: null,
      hostname: null,
      hash: null,
      search: '?name=zhangsan&password=123456',
      query: 'name=zhangsan&password=123456',
      pathname: '/chap4-16',
      path: '/chap4-16?name=zhangsan&password=123456',
      href: '/chap4-16?name=zhangsan&password=123456' }
    

    Chap4-16.html

    用户名: 密码:

    Chap4-16.js

    var http=require("http");
    var url=require("url");
    var queryString=require("querystring");
    http.createServer(function (req,res) {
        //可替换部分开始
        var query=url.parse(req.url).query;
        console.log(query);
        var params=queryString.parse(query);
        res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
        res.write("用户名为:"+params.user);
        res.end("密码为:"+params.password);
        //可替换部分结束
    }).listen(3000);
    console.log("HTTP server is listening at port 3000.");
    

    可替换部分:

    var query=url.parse(req.url,true).query;
    res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
    res.write("用户名为:"+query.user);
    res.end("密码为:"+query.password);
    
    获取 POST 请求内容

    POST 请求的内容全部都在请求体中。

    http.ServerRequest 并没有一个属性内容为请求体,原因是等待请求体传输可能是一件耗时的工作,譬如上传文件。所以 Node.js 默认是不会解析请求体的,当你需要的时候,需要手动来做。

    http.ServerResponse
    http.ServerResponseresponseres
    http.ServerResponse
    response.writeHead(statusCode, [headers])statusCode200404headersresponse.write(data, [encoding])dataBufferdataencodingutf-8response.endresponse.writeresponse.end([data], [encoding])response.write

    Chap4-18.html

    用户名: 密码:

    Chap4-18.js

    var http=require("http");
    var querystring=require("querystring");
    var util=require("util");
    http.createServer(function (req,res) {
        var post="";
        req.on("data",function (chunk) {
            post+=chunk;
        });
        req.on("end",function () {
            post=querystring.parse(post);
            res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
            res.write("用户名为:"+post.user);
            res.end("密码为:"+post.password);
        });
    }).listen(3000);
    console.log("HTTP server is listening at port 3000.");
    

    HTTP 客户端

    httphttp.requesthttp.get
    http.request(options, callback)http.ClientRequestoptioncallbackoption
    hostport80methodGETpath/QueryString/search?query=byvoidheaders
    http.get(options, callback)httpGEThttp.gethttp.requesthttp.getGETreq.end()

    Chap4-19.js

    var http=require('http');
    http.createServer(function (req,res) {
        res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
        //get 请求外网
        var html='';
        http.get('http://www.njfu.edu.cn',function(req1,res1){
            req1.on('data',function(data){
                html+=data;
            });
            req1.on('end',function(){
                res.end(html);
            });
        });
    }).listen(3000);
    console.log("HTTP server is listening at port 3000.");
    

    Chap4-20.js

    var http=require('http');
    var querystring=require('querystring');
    http.createServer(function (req,res) {
        res.writeHead(200,{"Content-Type":"text/html;charset=utf-8"});
        //发送 http Post 请求
        var postData=querystring.stringify({
            msg:'中文内容'
        });
        var options={
            hostname:'www.njfu.edu.cn',
            port:80,
            path:'/',
            method:'POST',
            headers:{
                'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',
                'Content-Length':Buffer.byteLength(postData)
            }
        };
        var html='';
        var req1=http.request(options, function(res1) {
            res1.setEncoding('utf-8');
            res1.on('data',function(chun){
                html+=chun;
            });
            res1.on('end',function(){
                res.end(html);
            });
        });
        req1.write(postData); // write data to request body
        req1.end();
    }).listen(3000);
    console.log("HTTP server is listening at port 3000.");
    

    Express框架

    • Express框架概述
    • 路由
    • 模板引擎
    • 数据库集成

    Express框架概述

    Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具。Express 作为开发框架,因为它是目前最稳定、使用最广泛,而且 Node.js 官方推荐的唯一一个 Web 开发框架。

    使用 Express 可以快速地搭建一个完整功能的网站。Express 框架核心特性:

    • 可以设置中间件来响应 HTTP 请求。
    • 定义了路由表用于执行不同的 HTTP 请求动作。
    • 可以通过向模板传递参数来动态渲染 HTML 页面。

    准备工作

    npm install express -g              //全局安装
    npm install express-generator -g    //安装全局变量
    
    cd example            //进入项目文件夹 
    express project       //创建express目录,project是目录名 
    
    cd project           //进入项目根目录 
    npm install          //安装依赖 
    

    最终目录:

    dependenciesnpm install

    app.js节略

    var createError = require('http-errors');
    var express = require('express');
    var path = require('path');
    var cookieParser = require('cookie-parser');
    var logger = require('morgan');
    // 路由信息(接口地址),存放在routes的根目录
    var indexRouter = require('./routes/index');
    var usersRouter = require('./routes/users');
    var app = express();
    // 模板开始
    app.set('views', path.join(__dirname, 'views'));
    app.engine('.html', require('ejs').__express);
    app.set('view engine', 'html');
    //略
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use('/', indexRouter);�app.use('/users', usersRouter);
    
    ejsnpm install ejs

    index.js

    var express = require('express');
    var router = express.Router();
    /* GET home page. */
    router.get('/', function(req, res, next) {
        res.type("text/html");
        res.render("home",{pic:"images/njfu.jpg"});   //重要
    });
    module.exports = router;
    

    users.js

    var express = require('express');
    var router = express.Router();
    /* GET users listing. */
    router.get('/', function(req, res, next) {
      res.type("text/html");
      res.send('

    Welcome to Nanjing Forestry University

    '); }); module.exports = router;

    home.html

    npm start
    node ./bin/www
    http://localhost:3000/http://localhost:3000/users

    Express网站的架构

    浏览器发起请求,由路由控制器接受,根据不同的路径定向到不同的控制器。控制器处理用户的具体请求,可能会访问数据库中的对象,即模型部分。控制器还要访问模板引擎,生成视图的 HTML,最后再由控制器返回给浏览器,完成一次请求。

    路由

    路由是指如何定义应用的端点(URIs)以及如何响应客户端的请求。

    路由是由一个 URI、HTTP 请求(GET、POST等)和若干个句柄组成,它的结构如下:

    router.METHOD(path, [callback...], callback)
    
    routerexpress.RouterRouterMETHODGETPOSTpathcallback
    // GET method route
    router.get('/', function (req, res) {
        res.send('GET request to the homepage');
    });
    // POST method route
    router.post('/', function (req, res) {
        res.send('POST request to the homepage');
    });
    

    路由路径

    路由路径和请求方法一起定义了请求的端点,它可以是字符串、字符串模式或者正则表达式。

    // 匹配根路径的请求 
    router.get('/', function (req, res) { 
        res.send('root'); 
    }); 
    // 匹配 /about 路径的请求 
    router.get('/about', function (req, res) { 
        res.send('about'); 
    }); 
    // 匹配 /random.text 路径的请求 
    router.get('/random.text', function (req, res) { 
        res.send('random.text'); 
    }); 
    // 匹配 acd 和 abcd 
    router.get('/ab?cd', function(req, res) { 
        res.send('ab?cd'); 
    }); 
    // 匹配 abcd、abbcd、abbbcd等 
    router.get('/ab+cd', function(req, res) { 
        res.send('ab+cd'); 
    }); 
    // 匹配 abcd、abxcd、abRABDOMcd、ab123cd等 
    router.get('/ab*cd', function(req, res) { 
        res.send('ab*cd'); 
    }); 
    // 匹配 /abe 和 /abcde 
    router.get('/ab(cd)?e', function(req, res) { 
        res.send('ab(cd)?e'); 
    }); 
    

    路由句柄

    next('route')

    路由句柄有多种形式,可以是一个函数、一个函数数组,或者是两者混合。

    app.js节略

    // 路由信息(接口地址),存放在routes的根目录
    var chap422Router = require('./routes/chap4-22');
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use("/chap4-22",chap422Router);
    

    chap4-22.js

    var express = require('express');
    var router = express.Router();
    router.get('/a', function (req, res) {
        res.type("text/html");
        res.send('

    Hello from A!

    '); }); router.get('/b', function (req, res, next) { console.log('response will be sent by the next function ...'); next(); }, function (req, res) { res.type("text/html"); res.send('

    Hello from B!

    '); }); var cb0 = function (req, res, next) { console.log('CB0'); next(); }; var cb1 = function (req, res, next) { console.log('CB1'); next(); }; var cb2 = function (req, res) { res.type("text/html"); res.send('

    Hello from C!

    '); }; router.get('/c', [cb0, cb1, cb2]); router.get('/d', [cb0, cb1], function (req, res, next) { console.log('response will be sent by the next function ...'); next(); }, function (req, res) { res.type("text/html"); res.send('

    Hello from D!

    '); }); module.exports = router;

    响应方法

    res
    res.download(path [, filename] [, callback])res.sendfile()
    pathfilename

    app.js节略

    app.get("/download",function (req, res) {
        var q = req.query;
        if (q.type == "jpg") {
            res.download(__dirname + "/public/images/njfu.jpg", "南林.jpg");
        } else if (q.type == "txt") {
            res.download(__dirname + "/public/files/content.txt");
        } else {
            res.send("错误的请求");
        }
    });
    
    res.end([data] [, encoding])
    res.json([body])
    res.redirect([status,] path)
    status: {Number}302path: {String}Location
    res.send([body])
    res.render(view [, option] [, callback(err,html)])
    viewoptioncallback(err,html)errhtmlres.send()

    app.js节略

    // 路由信息(接口地址),存放在routes的根目录
    var chap423Router = require('./routes/chap4-23');
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use("/chap4-23",chap423Router);
    

    chap4-23.js

    var express = require('express');
    var url = require('url');
    var router = express.Router();
    router.get('/redirect', function (req, res) {
        res.redirect("/chap4-22/a");
    });
    router.get('/end', function (req, res) {
        res.type("text/html");
        res.end("

    终结响应处理流程

    "); }); router.get('/json', function (req, res) { res.json({user:"Zhangsan",password:"123456"}); }); router.get('/render', function (req, res) { var newpath=url.resolve(req.url,"/images/njfu.jpg"); res.render("home",{pic:newpath},function (err,html) { if(err){ console.error(err); }else{ res.send(html); } }); }); module.exports = router;

    请求方法

    requestpostgetrequestrequest.paramsrequest.queryrequest.body
    // 路由信息(接口地址),存放在routes的根目录
    var chap426Router = require('./routes/chap4-26');
    //ejs模板
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use("/chap4-26",chap426Router);
    
    var express = require('express');
    var router = express.Router();
    router.get('/', function(req, res, next) {
        res.render('chap4-26');
    });
    router.post('/add', function (req, res) {
        res.type("text/html");
        res.write('

    姓名:'+req.body.name+'

    '); res.write('

    年龄:'+req.body.age+'

    '); res.end('

    职业:'+req.body.professional+'

    '); }); module.exports = router;
    姓名: 年龄: 职业:
    姓名: 年龄: 职业:
    router.get('/add1', function (req, res) {
        res.type("text/html");
        res.write('

    姓名:'+req.query.name1+'

    '); res.write('

    年龄:'+req.query.age1+'

    '); res.end('

    职业:'+req.query.professional1+'

    '); });
    
    
    router.get('/Update/:name', function (req, res) {
        res.type("text/html");
        res.send('

    姓名:'+req.params.name+'

    '); });

    模板引擎

    模板引擎(Template Engine)是一个从页面模板根据一定的规则生成 HTML 的工具。在 MVC 架构中,模板引擎包含在服务器端。控制器得到用户请求后,从模型获取数据,调用模板引擎。模板引擎以数据和页面模板为输入,生成 HTML 页面,然后返回给控制器,由控制器交回客户端。

    基于 JavaScript 的模板引擎有许多种实现,我们推荐使用 ejs(Embedded JavaScript),因为它十分简单,而且与 Express 集成良好。由于它是标准 JavaScript 实现的,因此它不仅可以运行在服务器端,还可以运行在浏览器中。

    在 app.js 中通过以下两个语句设置了模板引擎和页面模板的位置:

    app.js节略

    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    

    ejs 的标签系统非常简单,它只有以下3种标签。

    <% code %><%= code %><%- code %>

    chap4-24.ejs

    <%=title%>

    Welcome to <%=title%>

    chap4-24.js

    var express = require('express');
    var router = express.Router();
    router.use("/",function (req, res, next) {
        res.render("chap4-24",{title:"Express"});
    });
    module.exports = router;
    

    app.js节略

    // 路由信息(接口地址),存放在routes的根目录
    var chap425Router = require('./routes/chap4-25');
    // 模板开始
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use("/chap4-25",chap425Router);
    

    chap4-25.ejs

    
    
    
        
        EJS模板
        
    
    
    

    EJS模板引擎

    这是很简单的一个小流程就不在一一的标注流程了,注释的很清楚了

    这里是姓名: <%= name %>

    这里是性别: <%= sex %>

    这里是性别: <%= content %>

    chap4-25.css

    h1{    text-align: center;}
    p{    font-size:20px;}
    span{    font-size:25px;    color: red;}
    

    chap4-25.js

    var express = require('express');
    var router = express.Router();
    var data={
        name : 'webarn',
        sex : '男',
        content : '参数,可以更改'
    };
    router.use("/",function (req, res, next) {
        res.render("chap4-25",data);
    });
    module.exports = router;
    

    集成数据库

    为 Express 应用添加连接数据库的能力,只需要加载相应数据库的 Node.js 驱动即可。

    npm install mysql

    MySQL环境准备

    安装MySQL时配置参数:

    localhostroot0923
    localhosteducationdbcreate tableperson
    -- ----------------------------
    -- Table structure for person
    -- ----------------------------
    CREATE TABLE `person` (
      `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY,
      `name` varchar(255) DEFAULT NULL,
      `age` int(11) DEFAULT NULL,
      `professional` varchar(255) DEFAULT NULL,
    )
    -- ----------------------------
    -- Records of person
    -- ----------------------------
    INSERT INTO `person` VALUES ('1', '武大', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('2', '王二', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('3', '张三', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('4', '李四', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('5', '孙五', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('6', '钱六', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('7', '赵七', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('8', '刘八', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('9', '张九', '25', '计算机科学与技术');
    INSERT INTO `person` VALUES ('10', '郑十', '25', '计算机科学与技术');
    

    连接

    mysql模块是一个实现了MySQL协议的Node.js JavaScript客户端,通过这个模块可以与MySQL数据库建立连接、执行查询等操作。

    createConnection()connect()
    var mysql = require('mysql');
    var connection = mysql.createConnection({
        host: 'localhost',
        user: 'root',
        password: '0923',
        database: 'educationdb'
    });
    //可替换部分开始
    connection.connect(function(err) {
        if (err) {
            return console.error('连接错误: ' + err.stack);
        }
        console.log('连接ID ' + connection.threadId);
    });
    //可替换部分结束
    

    建立连接也可以隐式的由查询自动创建:

    可替换部分:

    connection.query('SELECT * from person', function(err, rows) {
        // 如果没有错误,则会连接成功!
    });
    

    在创建连接时,需要传入一些选项。可传入的选项参数如下:

    hostlocalhostport3306userpassworddatabaseconnectTimeout10000

    关闭数据库连接可以使用两种方法。

    connection.end(function(err) {
        // The connection is terminated now
    });
    
    connection.destroy();
    

    连接池

    数据库连接是一种有限的,能够显著影响到整个应用程序的伸缩性和健壮性的资源,在多用户的网页应用程序中体现得尤为突出。

    数据库连接池正是针对这个问题提出来的,它会负责分配、管理和释放数据库连接:允许应用程序重复使用一个现有的数据库连接,而不是重新建立一个连接;释放空闲时间超过最大允许空闲时间的数据库连接,从而避免因为连接未释放而引起的数据库连接遗漏。

    数据库连接池能明显提高对数据库操作的性能。

    createPool()
    end()
    pool.end(function (err) {
        // all connections in the pool have ended
    });
    
    getConnection()
    connection.release()
    connection.release()connection.destroy()

    db.js

    // 数据库包
    var mysql = require(‘mysql’);
    var pool = mysql.createPool({
        host: ‘localhost’,
        user: ‘root’,
        password: ‘0923’,
        database: ‘educationdb’
    });
    function query(sql, callback) {
        pool.getConnection(function (err, connection) {
            // Use the connection
            connection.query(sql, function (err, rows) {
                callback(err, rows);
                connection.release();//释放连接
            });
        });
    }
    exports.query = query;
    

    执行SQL语句

    对数据库的操作都是通过SQL语句实现的,通过SQL语句可以实现创建数据库、创建表、及对表中数据库的增/删/改/查等操作。

    node-mysqlConnectionPoolquery()SELECTquery()
    connection.query('SELECT * FROM `books` WHERE `author` = "David"', function (error, results, fields){});
    
    connection.query('SELECT * FROM `books` WHERE `author` = ?', ['David'], function (error, results, fields){});
    
    var post  = {id: 1, title: 'Hello MySQL'};
    var query = connection.query('INSERT INTO posts SET ?', post, function(err, result) {
        //...
    });
    console.log(query.sql); // INSERT INTO posts SET `id` = 1, `title` = 'Hello MySQL‘
    //标识符也可以使用??标识符占位符
    var userId = 1;
    var columns = ['username', 'email'];
    var query = connection.query('SELECT ?? FROM ?? WHERE id = ?', [columns, 'users', userId], function(err, results) {
        // ...
    });
    console.log(query.sql); // SELECT `username`, `email` FROM `users` WHERE id = 1
    
    connection.query({
      sql: 'SELECT * FROM `books` WHERE `author` = ?',
      values: ['David']
    }, function (error, results, fields) {});
    
    connection.query({
      sql: 'SELECT * FROM `books` WHERE `author` = ?',
    }, ['David'], function (error, results, fields) {});
    

    app.js节略

    // 路由信息(接口地址),存放在routes的根目录
    var persons = require('./routes/person');
    //ejs模板
    app.set('views', path.join(__dirname, 'views'));
    app.set('view engine', 'ejs');
    //配置路由,('自定义路径',上面设置的接口地址)
    app.use("/persons",persons);
    

    person.js

    var express = require('express');
    var router = express.Router();
    var db = require("./db.js");  //引入数据库包
    router.get('/', function (req, res, next) {
        db.query('select * from person', function (err, rows) {
            if (err) {
                res.render('persons', {title: '人员管理', datas: []});
            } else {
                res.render('persons', {title: '人员管理', datas: rows});
            }
        })
    });
    //删除
    router.get('/del/:id', function (req, res) {
        var id = req.params.id;
        db.query("delete from person where id=" + id, function (err, rows) {
            if (err) {
                res.end('删除失败:' + err)
            } else {
                res.redirect('/persons')
            }
        });
    });
    //新增
    router.get('/add', function (req, res) {
        res.render('add');
    });
    router.post('/add', function (req, res) {
        var name = req.body.name;
        var age = req.body.age;
        var professional = req.body.professional;
        db.query("insert into person(name,age,professional) values('" + name + "'," + age + ",'" + professional + "')", function (err, rows) {
            if (err) {
                res.end('新增失败:' + err);
            } else {
                res.redirect('/persons');
            }
        })
    });
    //修改
    router.get(‘/toUpdate/:id’, function (req, res) {
        var id = req.params.id;
        db.query(“select * from person where id=” + id, function (err, rows) {
            if (err) {
                res.end(‘修改页面跳转失败:’ + err);
            } else {
                res.render(“update”, {datas: rows});       //直接跳转
            }
        });
    });
    router.post('/update', function (req, res) {
        var id = req.body.id;
        var name = req.body.name;
        var age = req.body.age;
        var professional = req.body.professional;
        db.query("update person set name='" + name + "',age='" + age + "',professional= '" + professional + "' where id=" + id, function (err, rows) {
            if (err) {
                res.end('修改失败:' + err);
            } else {
                res.redirect('/persons');
            }
        });});
    //查询
    router.post('/search', function (req, res) {
        var name = req.body.s_name;
        var age = req.body.s_age;
        var professional = req.body.s_professional;
        var sql = "select * from person";
        if (name) {
            sql += " and name like '%" + name + "%' ";
        }
        if (age) {
            sql += " and age=" + age + " ";
        }
        if (professional) {
            sql += " and professional like '%" + professional + "%' ";
        }
        sql = sql.replace("person and","person where");
        db.query(sql, function (err, rows) {
            if (err) {
                res.end("查询失败:", err)
            } else {
                res.render("persons", {title: '人员管理', datas: rows});
            }
        });});
    module.exports = router;
    

    persons.ejs

    
    
    
        
        <%= title %>
        
    
    
    
    姓名:    年龄:    职业:   
    <% if (datas.length) { %> <% datas.forEach(function(person){ %> <% }) %> <% } %>
    编号 操作 姓名 年龄 职业
    <%= person.id %> 删除  修改 <%= person.name %> <%= person.age %> <%= person.professional %>

    add.ejs

    
    
    
        
        新增页面
    
    
    
    姓名: 年龄: 职业:

    update.ejs

    
    
    
        
        修改页面
    
    
    
    姓名: 年龄: 职业:

    地址 · ADDRESS

    地址:建邺区新城科技园嘉陵江东街18号2层

    邮箱:309474043@qq.Com

    点击查看更多案例

    联系 · CALL TEL

    400-8793-956

    售后专线:025-65016872

    业务QQ:309474043    售后QQ:1850555641

    ©南京安优网络科技有限公司 版权所有   苏ICP备12071769号-4  网站地图