PHP文件操作、表单处理和正则表达式

一、文件操作

一、打开关闭文件

1.fopen()

fopen()函数打开文件或者URL。如果打开失败,返回FALSE。

fopen(filename,mode,include_path,context) filename必需,规定要打开的文件或URL;mode必需,规定要求该文件/流的访问类型;include_path可选,如果也需要在include_path中检索文件,可以将参数设为1或TRUE;context可选,规定文件句柄的环境。

文件打开模式如下:

1
2
3
4
5
6
7
8
9
模式			可读?		可写?		文件指针		截断?		创建
r 是 否 开始 否 否
r+ 是 是 开始 否 否
w 否 是 开始 是 是
w+ 是 是 开始 是 是
a 否 是 结尾 否 是
a+ 是 是 结尾 否 是
文件指针:指向文件的开头或者是末尾
截断:如果文件已经存在,将文件指针指向文件头并将文件大小截为0

2.fclose()

fclose()函数关闭一个打开的文件。

fclose(file) file必需,规定要关闭的文件,file参数是一个文件指针。fclose()函数关闭该指针指向的文件,如果成功返回TRUE,否则返回FALSE。文件指针必须有效,并且是通过fopen()或fsockopen()成功打开的;虽然每个请求最后都会自动关闭文件,但明确的关闭打开所有文件是一个好的习惯。

运行如下:

1
2
3
4
5
//以只读方式打开一个位于本地服务器的文本文件
$fh = fopen("text.txt","r");
//以只读方式打开一个远程文件
$fh = fopen("http://www.xxx.com","r");
fclose($fh);
二、读取文件

1.fread()

fread()函数读取文件。

fread(file,length) file必需,规定要读取打开文件;length必需,规定要读取的最大字节数。fread()从文件指针file读取最多length个字节。该函数在读取最多length个字节数,或达到EOF时,读取将停止。

如果要读取整个文件,使用filesize()函数确定应该读取的字符数。

PHP运算符、流程控制、函数、数组和字符串

一、运算符

一、算数运算符

算数运算符用于完成各种运算。

1
2
3
4
5
+		加法运算符			$a+$b
- 减法运算符 $a-$b
* 乘法运算符 $a*$b
/ 除法运算符 $a/$b
% 取模运算符(求余数) $a%$b
二、赋值运算符

赋值运算符,将一个数据值赋给一个变量。

复合运算符,在赋值之前会完成某个运算。

1
2
3
4
5
6
$a = 5		赋值
$a += 5 加法赋值 $a = $a + 5
$a -= 5 减法赋值 $a = $a - 5
$a *= 5 乘法赋值 $a = $a * 5
$a /= 5 除法赋值 $a = $a / 5
$a .= 5 拼接赋值 $a = $a.5
三、字符串运算

字符串运算用于拼接字符串。

1
2
3
4
5
6
7
$a = "hello";
$b = $a . "world";//表示拼接前后两个字符串
echo $b;

$b = "Hello";
$b .= "World!";// .= 表示$b = $b."World!"
echo $b;
四、递增(++)和递减(–)运算符

递增和递减运算符将变量的当前值加1或减1,可以使代码更简洁。

1
2
3
4
++$i		先加  $i的值加1,然后再返回$i的值;
$i++ 后加 先返回$i的值,然后再将$i的值加1;
--$i 先减 $i的值减一,然后再返回$i的值;
$i++ 后减 先返回$i的值,然后再将$i的值减1;
五、逻辑运算符

利用逻辑运算符可以根据多个变量的值进行判断,这使得控制程序的流程成为可能,逻辑操作符常用于控制结构中,如if条件和while及for循环。

1
2
3
4
&&	and			逻辑与
|| or 逻辑或
! 逻辑非
xor 异或(有且仅有一个为true,则返回true)
六、比较运算符

比较运算符,返回一个布尔值TRUE或FALSE。

1
2
3
4
5
6
7
8
9
>		大于
< 小于
>= 大于或等于
<= 小于或等于
!= 不等于
<> 不等于
== 等于
=== 全等于(两个比较的内容里,类型也要相同)
!== 全不等
七、三元运算符

语法:expression1 ? expression2 : expression3

1
2
3
4
$a = 5;
$b = 2;
$res = $a > $b ? "yes" : "no";
echo $res;
八、运算符的优先级

运算符的优先级指的是哪一个运算符应该先计算。

具体运算符的优先级,请点击这里

二、流程控制

一、判断语句

1. if 语句

1
2
3
4
5
6
7
if(expression){
//statement;
}else if(expression){
//statement;
}else{
//statement;
}

if语句用括号中的表达式返回值(true或false)来控制是否执行指定的代码程序;表达式为数字0、空、未定义的字符串,内置常量都会返回false。

1
2
3
4
5
6
短路现象
$a = 5;
$num = 1;
if($a == 3 or $num++) {
echo $num;//输出1
}

2. switch 语句

语法格式:

1
2
3
4
5
6
7
8
9
switch (expression){
case value:
//statements;
break;
default:
//statements;
break;
}
在每个case块的末尾处都有break语句,如果没有break语句,就会执行所有后续的case块,直到遇到break语句为止。

switch 语句可以看做是if-else组合的一种变体,如果需要比较有限值的变量,通常会使用switch 语句。

二、循环语句

1. while

语法格式:

1
2
3
while (条件为真){
要执行的代码块;
}

2. do…while

do…while循环是while的一种变体,它在代码块的结束处验证循环条件。

do…while循环首先会执行一次代码块,然后检查条件,如果指定条件为真,则重复循环。

语法格式:

1
2
3
do{
要执行的代码块;
} while (条件为真);

3. for循环

当确定脚本的运行次数,可以使用for循环。

语法格式:

1
2
3
4
5
6
7
for (init counter; test counter; increment counter) {
code to be executed;
}
参数:
init counter:初始化循环计数器的值
test counter:评估每个循环迭代。如果为TRUE,继续循环;如果为FALSE,循环结束。
increment counter:增加循环计数器的值

4. foreach循环

foreach循环只适用于数组,并用于遍历数组中的每个键/值对。每次循环都将指针后移一位。

语法格式:

1
2
3
4
5
6
7
8
第一种:
foreach ($array as $value) {
code to be executed;
}
第二种:
foreach ($array as $key => $value) {
code to be executed;
}
三、跳出循环

1. break

如果包含一个break 语句,将立即结束 while、do.while、for、foreach、switch 的执行。

2. continue

continue 语句使当前循环执行结束,并从下一次循环开始执行。

三、函数

1. 函数概念

函数是用来完成某种特定任务的可重用代码块;

函数可以是程序更具模块化,拥有良好的结构;

函数定义后在程序中可以重复调用;

函数分为内置函数和自定义函数。

2. 函数分类

(1)内置函数

PHP 系统提供了大量功能强大的函数,帮助我们解决各种问题。

(2)创建自定义函数

语法格式:

1
2
3
function functionName() {
被执行的代码块;
}
3. 函数简介及区别

函数用function关键字来声明。

函数名称是由字母或下划线开头而非数字。

函数名不区分大小写,不过在调用函数的时候,通常使用其在定义时相同的形式。

PHP 不支持函数重载,所以自定义函数不能和内置函数重名。

参数出现在括号中,如果有多个参数,用逗号分隔。

不同语言函数的区别:

  1. 在Java等强类型语言中方法的名字严格区分大小写;
  2. C语言中的函数也是严格区分大小写;
  3. PHP 到现在的版本,函数名称不区分大小写;
  4. 很多语言允许函数的重载,即函数有相同的名称但是函数参数不同;
  5. PHP 不支持函数的重载。
4. 参数传递

值传递(传值)

函数内对参数值的改变不会影响函数外部的值。

引用传递(传址)

当需要在函数体内对参数地修改在函数体外也能反映时,用引用传递。

使用引用传递参数要在参数前加上&符号。

变量本身传入,传入后的变量与原变量建立联系,函数体内变量的变化,会影响到原变量本身。

1
2
3
4
5
$a = 25;
function modifyNum (&$num){
$num = 100;
}
modifyNum($a);

默认参数:可以为参数指定默认值,在没有提供其他值的情况下,则将默认值自动赋给该参数。

可选参数:可以指定某个参数为可选参数,这些参数需要放在参数列表的末尾,需要指定其默认值为空;如果指定了多个可选参数,可以选择性地传递某些参数。

5. 返回值

当需要将函数的执行结果返回给调用者时,这时可以使用return语句返回结果。

return语句执行后,将使得函数立即结束运行,并将控制权返回被调用的行。

1
2
3
4
5
6
7
8
function mysquare($num){
if($num == ""){
return;
}
$res = $x * $x;
return $res;
}
echo mysquare(4);
6. 变量作用域和生命周期

由于引入了函数,程序中变量的能见度发生了变化,即变量的作用范围发生了改变。变量分为:全局变量(global),局部变量(locak),静态变量(static)。

函数之外声明的变量拥有Global作用域,只能在函数以外进行访问。

函数内部声明的变量拥有Local作用域,只能在函数内部进行访问。

全局变量在函数内使用方法:

1
2
3
4
5
6
7
8
$user = "xiaoming";
function test(){
//方法一 php在名为$GLOBALS[index]的数组中存储了所有的全局变量。下标存有变量名。
//这个数组在函数内也可以访问,并能够用于直接更新全局变量。
$user = $GLOBALS["user"];
//方法二 在函数内部变量前面使用global关键字
global $user;
}

局部变量:函数体内定义的变量为局部变量,只在函数体内可见。

局部变量作用域:从声明它的那条语句开始到函数结束。

静态变量:当函数完成/执行后,会删除所有变量。不过,有时需要不删除某个局部变量。要完成这一点,在首次声明变量时使用static关键词。然后每当函数被调用时,这个变量所存储的信息都是函数最后一次被调用时所包含的信息。

静态变量使用方法:

1
2
3
4
5
6
7
8
function statics(){
static $num = 10;
$num++;
echo $num;
}
statics();
statics();
statics();
7. include和require
  1. include() include()语句将在其被调用的位置处包含一个文件,如include("init.php")

  2. include_once() include_once()的作用与include()相同,不过它会首先验证是否已经包含了该文件,如果已经包含,则不再执行include_once();

  3. require() 其与include()一样,只不过require()通常放在php程序的最前面;

  4. require_once() 其与include_once()一样,但是也要放在php程序的最前面;

  5. include与require的区别:require一个文件存在错误的话,那么程序就会中断执行,并显示致命错误;include一个文件存在错误的话,那么程序不会中断,而是继续执行,并显示一个警告错误。

四、数组

一、数组概念

数组为有序的(键-值)对组成的数据值的集合。根据索引值的不同,数组分为:索引数组和关联数组。

1
2
$day = array("a","b","c");//索引数组
$week = array("a"=>"星期一","b"=>"星期二","c"=>"星期三");//关联数组
二、数组创建

1.使用array()函数 $array = array([mixed ...])

与其他语言的数组实现方式不同,php不需要再创建数组时指定其大小。因为php是一种松散类型的语言,所以甚至不需要在使用前先声明。

索引可以是整型数字或则字符串:

  1. 索引数组:索引为整数,如果没有指定索引值则默认为零,依次递增;
  2. 关联数组:索引为字符串的数组。

2.直接对数组变量赋值 $arr[key] = value

1
2
3
4
$fruits[] = "orange";
$fruits[] = "apple";
$languages["en"] = "english";
$languages["cn"] = "chinese";

如果方括号中没有指定索引,则取当前最大整数索引值,新的键名将是 该值+1。如果当前还没有整数索引,则键名将为0.如果指定的键名已经有值了,该值将被覆盖。

3.使用函数创建数组 range()创建一个包含指定范围单位单元的数组。

1
2
3
4
$num = range(1,100);
print_r($num);
$letter = range("a","l");
print_R($letter);
三、数组的基本操作
  1. unset($arr[0]) 删除数组元素
  2. print_r($arr) 打印数组
  3. count($arr) 取得数组大小
  4. in_array(10,$arr) 检查数组中是否包含某个值
四、遍历数组
  1. for循环变量数组
  2. foreach循环遍历数组
五、数组排序
  1. sort()、rsort()对数组进行升序和降序。
  2. ksort()、krsort()对数组按索引进行升序或降序,并保持索引关系。
六、二维数组

数组元素的值也可以是数组。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$result = array(
array(
'name'=>'xiaoming',
'age'=>'18',
),
array(
'name'=>'xiaohong',
'age'=>'16',
),
);
//遍历二维数组
foreach($result as $keys => $values){
foreach($values as $key => $value){
echo "我是{$keys}的,我的键是{$keys},我的值是$values<hr/>";
}
}

五、字符串

一、输出字符串

echo 是一个语法,不是函数。echo没有返回值,echo可以输出多个值,使用逗号分隔。

二、其他处理函数

strlen() 获取字符串长度

strtolower() 将字符串转换为小写字母

strtoupper() 将字符串转换为大写字母

三、查找与替换

strpos()

strpos(string,find[,start]) strpos()函数在string中以区分大小写的方式找到find第一次出现的位置;如果没有找到则返回FALSE;可选参数start指定开始查找的位置。

stripos()

stripos()与strpos()功能相同,只是查找时不区别大小写。

str_replace()

str_replace(search,replace,subject[,count])

str_replace()函数在subject中以区分大小写的方式搜索search,用replace替换找到的所有内容;如果没有找到search,则subject保持不变。count对替换数进行计数的变量,不可对其设置。

str_ireplace()

str_ireplace()与str_replace()功能相同,只是不区分大小写。

四、截取字符串

substr()

substr(string,start[,length]) 从start位置取出length长度的字符,字符串位置开始值为0;如果没有指定length,那么默认一直到字符串末尾。

strstr()

strstr(string,search,before_search) strstr()作业从string中搜索search,并根据第三个参数返回search后面的数据还是前面的数据(默认为false,返回search后面的;true,返回search前面的)。

stristr()

stristr()与strstr()功能相同,只是不区分大小写。

五、删除字符串

ltrim()

lstrim(string,[charlist]) ltrim函数删除字符串左侧空格及其他预定义字符;如果未设置charlist参数,则删除一下字符:

  1. “\0” NULL
  2. “\t” 制表符
  3. “\n” 换行
  4. “\x0B” 垂直制表符
  5. “\r” 回车
  6. “ “ 空格

rtrim()

rtrim(string[,charlist]) rtrim函数删除字符串右侧空格或其他预定义字符。

trim()

trim函数删除字符串两侧空格或其他预定义字符。

strrev() 反转字符串

nl2br() 将字符串中换行(\n)转换成HTML换行标签(br/)。

strip_tags()

strip_tags(string[,allowable_tags]) 删除字符串中 HTML XML PHP 标签,可选参数allowable_tags指定要保留的标签。

htmlspecialchars() 函数把一些预定义的字符转换为HTML实体

预定义的字符有:

  1. & (和号) 成为 &amp;
  2. "" (双引号) 成为 &quot;
  3. '' (单引号) 成为 &#039;
  4. < (小于) 成为 &lt;
  5. > (大于) 成为 &gt;
六、数组字符串转换

explode()

explode(separator,string[,limit]) 返回由字符串组成的数组,separator规定在哪里分隔字符串,string要分割的字符串,可选limit规定所返回的数组元素的数目。

implode()

implode([separator,]array) 将数组元素连接成字符串,separator可选规定数组元素之间放置的内容,默认是””(空字符串);array要组合为字符串的数组。

PHP初了解

PHP 简介

PHP 是一种创建动态交互性站点的强有力的服务器端脚本语言。

PHP 脚本在服务器上执行。

PHP 文件必须为英文名,防止出现错误;PHP 代码必须加分号。

  1. PHP 是 “PHP Hypertext Preprocessor” (超文本预处理器)的缩写。
  2. PHP 是一种被广泛使用的开源脚本语言。
  3. PHP 脚本在服务器上执行。
  4. PHP 可以免费下载和使用。

PHP 文件:

  1. PHP 文件能够包含文本、HTML、CSS 以及 PHP 代码。
  2. PHP 代码在服务器上执行,而结果以纯文本返回浏览器。
  3. PHP 文件的后缀是 “.php”。

PHP 优点:

  1. 开源
  2. 能运行于各种平台(Windows,Linux,Unix,Mac OS X 等等)
  3. 兼容几乎所有的服务器
  4. 语法简单,极易学习
  5. 功能强大,能做大型开发
  6. 能够动态生成web页面内容(php代码可以嵌入到html代码中)

环境搭建

通过XAMPP(Apache+MySQL+PHP+Perl)建站集成软件包来安装。使用XAMPP目的是因为手动安装Apache+MySQL+PHP环境过于复杂,使用XAMPP只需点击安装即可。

XAMPP常见问题

  1. Apache启动失败:运行sudo apachectl stop
  2. MySQL启动失败:(1)sudo /Library/StartupItems/MySQLCOM/MySQLCOM stop (2)使用ps-eflgrep mysql查找进程号,通过kill杀掉进程

PHP 基础语法

PHP脚本以<?php开头,以?>结尾:

1
2
3
<?php
//此处是 PHP 代码
?>

PHP注释:

  1. 多行注释
  2. 单行注释
  3. 文档注释
1
2
3
4
5
6
7
8
9
10
11
12
1.多行注释
/*
注释内容
注释内容
*/
2.单行注释
//注释内容
3.文档注释
/**
*注释文档
*注释文档
*/

变量的声明:

  1. 变量以$开头,后面跟变量名
  2. 变量只能由字母,数字,下划线组成,不能以数字开头
  3. 变量名区分大小写
  4. PHP 与 JavaScript 类似,不需要实现声明变量的数据类型
1
2
$name = "xiaoming";
$age = 18;

变量的赋值:

  1. 值赋值:即将赋值表达式的值复制给变量(直接赋值);
  2. 引用赋值:创建的一个变量与另一个变量引用的内容相同(引用相同地址)。
1
2
$var = "hello";
$var1 = &$var;//把变量var的引用赋值给var1

变量的变量:

1
2
3
4
5
$say = "hello";
$$say = "world";//相当于$hello = "world";
echo $say;//输出hello
echo $hello;//输出world
echo ${$ay};//输出world

超全局变量:

PHP提供很多预定义变量,用于提供大量与环境有关的信息

打印/输出超全局变量:print_r($_SERVER);

1.$_SERVER 服务器变量,该全局变量包含着服务器和客户端配置及当前请求环境的有关信息

$_SERVER[‘SERVER_NAME’] : 当前运行脚本所在的服务器的主机名

$_SERVER[‘REMOTE_ADDR’] : 客户端IP地址

$_SERVER[‘REQUEST_URI’] : URL的路径部分

$_SERVER[‘HTTP_USER_AGENT’] : 操作系统和浏览器的有关信息

2.$_GET 该变量包含使用GET方法传递的参数地有关信息

3.$_POST 该变量包含使用POST方法传递的参数地有关信息

4.$_REQUEST 该变量记录着通过各种输入方法传递给脚本的变量,如GET POST,但是不建议使用,因为它不安全而且速度较慢

5.$_COOKIE cookie变量数组

6.$_SESSION 会话变量数组

7.$_FILES 与上传文件有关的变量数组

8.$_ENV 环境变量数组

9.$GLOBALS 所有全局变量数组

常量:

常量是指在程序执行中无法修改的值。

  1. 在脚本执行期间该值不能改变;
  2. 常量对大小写敏感,通常常量名总是大写;
  3. 常量是全局的,可以在脚本的任何地方引用;
  4. 常量分为内置常量和自定义常量;
  5. 常量使用define()函数定义。
1
2
define('PI',3.1415926,false);//第三个参数:是否对大小写敏感(默认false对大小写敏感;true对大小写不敏感)
echo PI;//3.1415926

一、内置常量

PHP_OS PHP 所在操作系统的名称

PHP_VERSION 当前PHP 的版本号

二、魔术常量

__LINE__ 文件中的当前行号

__FILE__ 文件的完整路径和文件名

__FUNCTION__ 函数名称

__CLASS__ 类的名称

__METHOD__ 类的方法名

数据类型

标量数据类型

一、字符串

字符串有三种定义方式:单引号,双引号,定界符(heredoc);

单引号字符串中出现的变量不会被变量的值替代;

双引号字符串中最重要的一点是其中的变量会被变量值替代;

如果遇到美元符号($),解析器会尽可能多地取得后面的字符以组成一个合法的变量名,如果想明确的制定名字的结束,用{}把变量名包括起来。

字符串定界的方法使用定界符语法<<<

1
2
3
4
5
$str = <<< EOD
Example of string
using heredoc syntax.
EOD;
echo $str;

在PHP 定界符中的任何特殊字符,都不需要转义,PHP 定界符中的PHP变量会被正常的用其值来替换。

使用定界符要注意:结束标识符所在的行不能包含任何其他字符,这意味着该标识符不能被缩进,在分号之前、之后都不能有任何空格或制表符。

1
2
3
4
5
6
7
字符串转义
\n 换行
\r 回车
\t 水平制表符(tab键)
\\ \(反斜杠)
\$ $(美元符)
\" "(双引号)

二、整型(integer)

整型是没有小数的数字。整型必须有至少一个数字(0-9);整型不能包含逗号或空格;整型不能有小数点;整型正负均可;可以用三种格式规定整型:十进制、十六进制或八进制。

三、浮点型(float,double)

浮点数是有小数点或指数形式的数字,分为单精度(float)和双精度(double)

四、布尔型(bool)

布尔型指true或false。

复合数据类型

一、数组

数组在一个变量中存储多个值。

二、对象

特殊数据类型

一、资源

$fh = fopen("text.txt","r");

二、null

null 无,表示没有值,null不表示空格,也不表示0。

以下情况认为是null:

  1. 没有设置为任何预定义的变量;
  2. 明确的赋值为null;
  3. 使用函数unset()清除。
自动类型转换

因PHP 对于类型定义非常的松散,所以有时候会根据引用变量的环境,将变量自动转换为最适合的类型。

1
2
3
4
5
6
7
8
9
10
11
12
$num = 5;
$str = "15";
echo $num + $str;

$str = "100 hehe";
$num = 200;
echo $num + $str;

$str = "1.5";
if($str){ //if判断为true
echo "hello world";
}
类型相关函数

1.gettype() 返回变量的类型,可能的值有 string、integer、float、boolean、array、object、null、unknown。

2.is_type() 查看变量是否属于某个类型,是返回TRUE,否返回FALSE。

3.var_dump() 获取变量的值和类型的详细信息。

HTML5canvas标签和JavaScript的结合运用

Canvas简介

Canvas是HTML5中重要的元素,其和audio、video元素类似,完全不需要任何外部插件就能运行。

Canvas中文翻译为“画布”。它提供了强大的图形处理功能(绘制,变换,像素处理等)。

Canvas浏览器支持:除IE8及以下不支持外,其他浏览器都支持Canvas。

Canvas标签

<canvas>标签定义图形,<canvas>标签只是图形容器,必须使用脚本来绘制图形。

<canvas>您的浏览器不支持canvas</canvas>canvas标签中的内容在支持的浏览器内,默认为不显示;在不支持的浏览器上才会显示。

canvas属性:width宽 height高,假如不设置宽高属性,默认为宽300像素高150像素。

在进行图形绘制时,我们是通过context绘图环境进行操作的。

大多数 Canvas 绘图 API 都没有定义在 <canvas> 元素本身上,而是定义在通过画布的 getContext() 方法获得的一个“绘图环境”对象上。

context是canvas的核心。context字面意思是上下文,我们可以理解为绘图的助手,用于存储操作步骤。

canvas坐标系:X轴:横向向右为正方向;Y轴:竖向向下为正方向。

canvas标签的使用:

1
2
3
4
5
6
7
8
9
10
11
<body>
<canvas id="canvas1" width="500" height="500">
您的浏览器不支持canvas,请使用高版本的浏览器
</canvas>
<script type="text/javascript">
//获取canvas
var canvas = document.getElementById("canvas1");
//获取绘制环境
var context = canvas.getContext("2d");
</script>
</body>

Canvas基本图形绘制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
基本图形绘制

beginPath() 开始一条路径

moveTo(x,y) 设置绘制起点

lineTo(x,y) 设置下一个点

closePath() 闭合路径,会从当前点连接到起始点,形成一个封闭的路径

strokeStyle 设置线条的样式(颜色)

stroke() 绘制线条

fillStyle 设置填充样式(颜色)

fill() 填充当前绘图

lineWidth 设置线宽

strokeRect(x,y,w,h) 绘制矩形边框,x,y分别为起始绘制x轴y轴的位置,w为绘制宽度,h为绘制高度

fillRect(x,y,w,h) 填充矩形边框

arc(x,y,radius,startAngle,endAngle,anticlockwise)

x,y:圆心位置 ;radius:半径;startAngle,endAngle:开始/结束角度(以弧度计算);anticlockwise:true逆时针false顺时针;

strokeText() 绘制文字

fillText() 填充文字

createLinearGradient(x0,y0,x1,y1); x0,y0:渐变开始点;x1,y1:渐变结束点

font 字体样式

阴影设置(当设置阴影后,所有的图形都会有阴影)

shadowColor 阴影颜色

shadowOffsetX X方向偏移量

shadowOffsetY Y方向偏移量

shadowBlur 设置阴影的模糊级别

图形变换

translate(x,y) 平移(当设置平移时,整个context都会发生移动,也就是坐标系发生变化)

rotate(deg) 旋转,单位为弧度(当发生旋转时,坐标系也会发生变化,通常搭配translate使用)

scale(x,y) 缩放,x、y分别为x轴和y轴方向缩放(当发生缩放时,坐标系也会相应的变化)

状态保存和获取(遵循“先进后出,后进先出”的原则)

save() 存储绘制状态

restore() 获取之前的画布状态

贝塞尔曲线

quadraticCurvaTo(cpx,cpy,dx,dy) 创建一条表示二次曲线的路径(二次曲线就是二次函数形成的曲线)
cpx,cpy代表控制点,决定曲线的形状 dx,dy代表终点位置

bezierCurveTo(cpx,cpy,cpx2,cpy2,dx,dy) 创建一条表示贝塞尔曲线的路径
cpx,cpy,cpx2,cpy2代表两个控制点的位置,决定曲线的形状 dx,dy代表终点位置

设置文字及颜色渐变:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<style>
#canvasfont{
box-shadow:0 0 20px lightgreen;
}
</style>
<canvas id="canvasfont" width="300" height="300">
您的浏览器不支持;
</canvas>
<script>
var canvasfont = document.getElementById("canvasfont");
var contextfont = canvasfont.getContext("2d");
//设置文字
var text = "hello World!";
contextfont.font = "40px 宋体";
//设置渐变
var fontgradient = contextfont.createLinearGradient(10,50,300,300);
fontgradient.addColorStop("0","blue");
fontgradient.addColorStop("0.5","gold");
fontgradient.addColorStop("1","purple");
//设置填充颜色
contextfont.fillStyle = fontgradient;
//开始填充文字
contextfont.fillText(text,30,50);
//填充矩形
contextfont.fillRect(10,60,280,230);
</script>
    
    
        您的浏览器不支持;
    
    

Canvas进阶

globalCompositeOperation属性

设置或返回如何将一个源(新的)图像绘制到目标(已有)的图像上。源图像就是打算放置到画布上的绘图。目标图像是已经放置在画布上的绘图。

其属性值为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
source-over			默认。在目标图像上显示源图像

source-atop 在目标图像顶部显示源图像。源图像位于目标图像之外的部分是不可见的

source-in 在目标图像中显示源图像。只有目标图像内的源图像部分会显示,目标图像是透明的

source-out 在目标图像之外显示源图像。只会显示目标图像之外源图像部分,目标图像是透明的

destination-over 在源图像上方显示目标图像

destination-atop 在源图像顶部显示目标图像。源图像之外的目标图像部分不会被显示

destination-in 在源图像中显示目标图像。只有源图像内的目标图像部分会被显示,源图像是透明的

destination-out 在源图像外显示目标图像。只有源图像外的目标图像部分会被显示,源图像是透明的

lighter 显示源图像 + 目标图像(会使重叠部分颜色叠加)

copy 显示源图像。忽略目标图像

source-over 使用异或操作对源图像与目标图像进行组合
图像绘制
1
2
3
4
5
6
drawImage(image,x,y)				在canvas中x,y处绘制图片

drawImage(image,x,y,width,height) 在canvas中x,y处绘制图片,并将其缩放到指定的宽度和高度

drawImage(image,sourceX,sourceY,sourceWidth,sourceHeight,x,y,width,height)
从图片中切割出一个矩形区域(sourceX,sourceY,sourceWidth,sourceHeight),缩放到指定的宽度和高度,并在canvas中x,y绘制出来
1
2
3
4
5
6
7
8
9
10
var img = new Image();
img.src = "图片路径";
img.onload = function (){
//载入图片
context.drawImage(img,0,0);
//控制图片
context.drawImage(img,0,0,canvas,width,canvas.height);
//裁减
context.drawImage(img,0,0,100,100,50,50,img.width,img.height);
}
像素

getImageData()返回ImageData对象,该对象拷贝了画布指定矩形的像素数据。

ImageData中三个属性:width,height和data。width和height表示访问像素区域大小,data是一个包含访问区域所有像素信息的CanvasPixeArray,CanvasPixeArray是一个一维数组。

对ImageData中的每个像素,都存在这四方面的信息,即RGBA值:

  1. R - 红色(0-255)
  2. G - 绿色(0-255)
  3. B - 蓝色(0-255)
  4. A - alpha通道(0-255;0是透明,255是完全可见的)
1
2
3
4
getImageData(x,y,width,height)		获取像素。x,y像素区域雨点坐标,width,height像素区域的宽度和高度

putImageData(imgData,x,y,dirtyX,dirtyY,dirtyWidth,dirtyHeight)
插入像素。imgData像素对象、在画布上显示的x,y、从哪个位置开始展示x,y,展示的宽度,高度(后四个为可选参数)

插入图片示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
var img = new Image();
img.src = "图片路径";
img.onload = function (){
context.drawImage(img,0,0);
var imgData = context.getImageData(0,0,canvas.width,canvas.height);
var pixs = imgData.data;
//因为一个参数是以四个参数组合的,所以i+=4
for(var i=0;i<pixs.length;i+=4){
var r = pixs[i];
var g = pixs[i+1];
var b = pixs[i+2];
var gray = parseInt((r+g+b)/3);
//图像反色
pixs[i] = gray;
pixs[i+1] = gray;
pixs[i+2] = gray;
}
context.putImageData(imgData,img.width,img.height);
}
视频的处理
1
2
3
4
5
6
7
8
9
10
11
12
function animate(){
if(!video.ended){
//将视频的每一帧都绘制在canvas上
context.drawImage(video,0,0,canvas,width,canvas.height);
widow.requestAnimationFrame(animate);
}
}
//当视频可以播放时,进行播放调用循环
video.oncanplay = function(){
video.play();
window.requestAnimationFrame(animate);
}

requestAnimationFrame:动画帧

requestAnimationFrame不需要使用者指定循环间隔时间,浏览器会基于当前页面是否可见、CPU的负荷情况等来自行决定最佳的帧速率,从而更合理地使用CPU。

通过setTimeout和setInterval方法在脚本中可实现动画,但是这样的效果可能不够流畅,而且会占用额外的资源。

  1. 即使向其传递毫秒为单位的参数,它们也不可能达到毫秒的准确性。这是因为JavaScript是单线程的,可能会发生阻塞。
  2. 没有对调用动画的循环机制进行优化。
  3. 没有考虑到绘制动画的最佳时机,只是一味地以某个大致的事件间隔来调用循环。
图形的存储

通过toDataURL()来生成图片链接实现

1
2
3
4
5
6
7
8
9
<script>
var canvas = document.getElementById("canvas");
var context = canvas.getContext("2d");
context.fillRect(100,100,100,100);
//输出
var url = canvas.toDataURL();
//在网页中显示
window.location.href = url;
</script>

jQuery函数的封装

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
<script>
//首先封装对象的获取方法
function getEles(arg){
//用正则判断开头和结尾是否一个或有多个空格
var reg1 = /^\s*|\s*$/g;
arg = arg.replace(reg1,"");
//用正则判断中间是否有空格,假如有替换成一个空格
var reg2 = /\s+/g;
arg = arg.replace(reg2," ");
//将arg通过空格来分割成需要的数组
var elArr = arg.split(" ");
var result = [];
var parents = [document];
//对arg进行遍历,找到选中的arg
for(var i=0;i<elArr.length;i++){
result = [];
for(var j=0;j<parents.length;j++){
//通过if分别判断需要使用id、class或者tagName选择器
if(/^#/.test(elArr[i])){
//通过字符串截取,去掉单词开头的#号
var idName = elArr[i].substring(1);
//找到对应的对象,并将其推入数组
var idArr = document.getElementById(idName);
result.push(idArr);
}else if(/^\./.test(elArr[i])){
var className = elArr[i].slice(1);
var classArr = findClass(parents[j],className);
for(var k=0;k<classArr.length;k++){
result.push(classArr[k]);
}
}else{
var tagArr = parents[j].getElementsByTagName(elArr[i]);
for(var k=0;k<tagArr.length;k++){
result.push(tagArr[k]);
}
}
}
parents = result;
}
return parents;
}
//封装获取class,主要因为需要兼容IE浏览器
function findClass(obj,className){
if(window.getElementsByClassName){
return obj.getElementsByClassName(className);
}else{
//因为IE支持tagName选择器,所以首先找到obj下的所有标签,然后通过正则来找到需要的className
var tagArr = obj.getElementsByTagName("*");
var classArr = [];
var reg = new RegExp("\\b"+className+"\\b");
for(var k=0;k<tagArr.length;k++){
if(reg.test(tagArr[k].className)){
classArr.push(tagArr[k]);
}
}
return classArr;
}
}

//jQuery标志为$,所以封装函数来模拟
function $(arg){
return new Jq(arg);
}

//创建构造函数Jq
function Jq(arg){
//通过创建一个数组来记录选择到的对象
this.elements = [];
//因$(arg)能传三种形式,所以对其进行判断
if(typeof(arg) == "function"){
ready(arg);
}else if(typeof(arg) == "string"){
this.elements = getEles(arg);
}else{
this.elements.push(arg);
}
}
//因Jq(function)的函数是在html、css和js都加载完成时才运行的,所以需要对其进行判断
function ready(fn){
if(window.addEventListener){
document.addEventListener("DOMContentLoaded",fn,false);
}else{
var oS = document.createElement("script");
oS.defer = true;
var oH = document.getElementsByTagName("head")[0];
oH.appendChild(oS);
oS.onreadystatechange = function(){
if(oS.readyState == "complete"){
fn();
}
}
}
}

//对其原型设置click方法,模拟jQuery的click()方法
Jq.prototype.click = function(fn){
for(var i=0;i<this.elements.length;i++){
addEvent("click",fn,this.elements[i]);
}
}
//因添加click时,需要涉及到IE的兼容,所以封装一个函数
function addEvent(event,fn,obj){
if(obj.addEventListener){
obj.addEventListener(event,fn,false);
}else{
obj.attachEvent("on"+event,fn);
}
}

//对其原型设置on方法,模拟jQuery的on()方法
Jq.prototype.on = function(event,fn){
//因有可能会设置"click mouseleave"等多事件,所以将其分成数组
var eventArr = event.split(" ");
for(var i=0;i<this.elements.length;i++){
for(var j=0;j<eventArr.length;j++){
addEvent(eventArr[j],fn,this.elements[i]);
}
}
}

//对其原型设置.css方法,模拟jQuery的css()方法
Jq.prototype.css = function(){
//因css(arg)有三种情况,所以对其分别设置
if(arguments.length == 1){
if(typeof(arguments[0]) == "string"){
//当只有一个属性时,是获取属性值,需要返回出去
return getStyle(this.elements[0],arguments[0]);
}else{
//当其为JSON数据时,就是设置
for(var i=0;i<this.elements.length;i++){
//通过使用for in循环来获得JSON的内容
for(var keys in arguments[0]){
setStyle(this.elements[i],keys,arguments[0][keys]);
}
}
}
}else if(arguments.length == 2){
for(var i=0;i<this.elements.length;i++){
setStyle(this.elements[i],arguments[0],arguments[1]);
}
}
}
//因需兼容IE浏览器,所以封装getStyle函数
function getStyle(obj,style){
if(window.getComputedStyle){
return getComputedStyle(obj,null)[style];
}else{
return obj.currentStyle(style);
}
}
//因需兼容IE浏览器,所以封装setStyle函数
function setStyle(obj,styleName,styleValue){
//因jQuery中width、height、left、top仅写数字时也是生效的,所以需要加个判断
var selectArr = ["width","height","left","top"];
for(var i=0;i<selectArr.length;i++){
if(selectArr[i] == styleName){
if(typeof(styleValue) == "number"){
styleValue = styleValue + "px";
}
}
}
obj.style[styleName] = styleValue;
}

//对原型设置eq()的方法
Jq.prototype.eq = function(index){
return new Jq(this.elements[index]);
}
</script>

JavaScript面向对象

JavaScript面向过程编辑与面向对象编辑

面向过程编辑:

  1. 注重解决问题的步骤,分析问题需要的每一步,实现函数的依次调用。

  2. 代表编程语言:C语言。

  3. 面向过程的思维方式就是典型的计算机思维方式:输入数据给处理器,处理器内部执行,然后处理器返回结果。

面向对象编辑:

  1. 面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为。

  2. 代表编程语言:JavaScript,Java,C++,C#

  3. 面向对象编程就是抛开计算机思维,使用生活中的思维方式进行的编程方式。生活中,每一件事物都有自己的状态和行为,因此可以这么说——万事万物皆对象。

  4. 基本特征:封装,继承,多态。

面向过程编辑与面向对象编辑的区别和联系
  1. 面向过程编程:注重解决问题的步骤,分析问题需要的每一步,实现函数依次调用。

  2. 面向对象编辑:注重问题中的对象,分析问题中对象的联系,实现对象间的通讯解决问题。

  3. 面向对象编程淡化过程,强调对象。 更接近我们日常处理问题的方式。

  4. 面向过程:所有功能都是在需要使用的时候才开发,相当于去餐馆点菜,现点现做,需要等待时间。

  5. 面向对象:在正式开发之前,就先把所有需要使用的功能开发好,并以属性或者方法的形式存放在一个对象中,在实际开发的时候根据需要来调用写好的功能。相当于去麦当劳,食物都是做好的,去了直接就可以吃了。

  6. 面向对象无法取代面向过程,他们是相辅相成的。面向对象关注于从宏观上把握事物之间的关系,在具体到如何实现某个细节时,仍然采用面向过程的思维方式。面向对象如果离开了面向过程,就无法实现真正的落地,成为无源之水。

面向对象——类和对象

类:类是一组具有相同特征和事物的抽象。

一个对象所包含的所有数据和代码可以通过类来构成一个用户定义的数据类型。事实上,对象就是类类型(class type)的变量。一旦定义了一个类,就可以创建这个类的多个对象,每个对象与一组数据有关,而这个数据的类型在类中定义。

对象:对象是类的实例,对象是具体的事物。

在一个面向对象的系统中,对象是运行期的基本实体。它可以用来表示一个人,一辆车,一个账户,或者是需要被程序处理的东西。它也可以用来表示用户定义的数据,例如一个变量,列表等。在面向对象的程序设计中,问题的分析一般以对象及对象间的自然联系为依据。对象在内存中占有一定空间,并且具有一个与之关联的地址。

当一个程序运行时,对象之间通过互发消息来相互作用。每个对象都包含数据以及操作这些数据的代码。即使不了解彼此的数据和代码的细节,对象之间依然可以相互作用,所要了解的只是对象能够接受的消息的类型,以及对象返回的响应的类型,虽然不同的人会以不同的方法来实现。   

Object对象的使用

只有对象才有属性和方法,基本数据类型没有。

string等类型能够使用的方法来自于他自身的构造器,在基本数据类型调用方法时会临时创建一个对象出来,在方法完成时,自动销毁。

    //使用Object声明对象
    var student = new Object();
    //简写方法
    var student = {};
    //设置属性
    student.name = "小明";
    student.sex = "男";
    //方法
    student.say = function(){
        alert(this.name+"\n"+this.sex);
    }
    //调用方法
    student.say();

工厂模式

    function Student(name,sex){
        //内部创建对象
        var obj = {};
        //属性
        obj.name = name;
        obj.sex = sex;
        //方法
        obj.showName = function(){
            alert(obj.name);
        }
        obj.showSex = function(){
            alert(obj.sex);
        }
        //返回对象
        return obj;
    }
    //使用工厂模式创建对象
    var xiaoMing = Student("小明","男");
    //调用方法
    xiaoMing.showName();
    xiaoMing.showSex();

构造函数和原型

构造函数:用来构建对象的函数。

  1. 为了区别普通函数,构造函数的函数名首字母规定为大写形式。

  2. 构造函数必须使用new运算符来调用执行(实例化对象)。

原型:prototype 当我们声明一个类时,同时生成了一个对应的原型。

  1. 通过new实例化出来的对象,其属性和行为来自于两个部分,一部分来自于构造函数,另一部分来自于原型。

  2. 原型本身就是一个对象。

  3. 通过prototype可以指向这个原型,原型可以通过constructor指向类(构造函数)。

一般来说,我们习惯把属性放在构造函数中,把方法放在原型中。目的是节省性能,因为实例化对象不一定每个都需要方法。

原型链:原型链是指对象在访问属性或方法时的查找方式。

  1. 当访问一个对象的属性或方法时,会现在对象自身上查找属性或方法是否存在,如果存在就使用自身的属性或方法;如果不存在就去创建的构造函数的原型对象中查找,如果有就使用,没有就继续向上查找,以此类推,知道找到为止。如果到顶层对象中还找不到,则返回undefined。(当原型和构造函数都有的时候,找到的是其本身,因为原型链是先从对象自身查找的)

  2. 原型链最顶层为Object构造函数的prototype原型对象,给Object.prototype添加属性或方法可以被除null和undefined之外的所有数据类型对象使用。

    //创建构造函数  类似 类
    //特征:首字母大写
    //一般情况下,把属性放在构造函数中,把方法放在原型中
    function Student(name,sex){
        this.name = name;
        this.sex = sex;
    }
    Student.prototype = {
        say : function(){
            alert("姓名:"+this.name+"\n"+"性别:"+this.sex);
        }
    }
    //向原型中追加属性或方法,必须放在原型对象下方,否则就会被覆盖
    Student.prototype.height = "180cm";
    //实例化对象
    var student = new Student("小红","女");
    //调用方法
    student.say();

面向对象基本特征

特征一:封装

封装的目的在于将信息隐藏。封装机制将数据和代码捆绑到一起,避免了外界的干扰和不确定性,可以创建对象。简单的说,一个对象就是一个封装了数据和操作这些数据的代码的逻辑实体。

在一个对象内部,某些代码和(或)某些数据是可以私有的,不能被外部访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外改变或错误的使用了对象的私有部分。在传统的面向对象的语言中,一般会提供public、protected、private等关键字来声明属性和方法的公开性;而JavaScript没有这些关键字,主要通过作用域来实现公有或私有。

因为私有属性及私有方法只能在构造函数内部进行直接访问,因此通过公有的方法去访问私有的属性。

set方法专门给私有属性赋值的方法称为set方法。

get方法专门获取私有属性的方法称为get方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function Women(name,sex){
//共有属性
this.name = name;
this.sex = sex;
//私有属性
var _age = "20";
//公有方法
this.eat = function(){
alert("吃了啥");
}
//私有方法
var fight = function(){
alert("go go go!");
}
//私有属性及私有方法只能在构造函数内部进行直接访问。
//set方法及其合法性
this.setAge = function(age){
if(parseInt(age)>100 || parseInt(age)<0){
alert("年龄不合法");
return;
}
_age = age;
}
//get方法
this.getAge = function(){
return _age;
}
}
特征二:继承

继承可以让某个类型的对象获得另一个对象的属性的方法。继承的特性是子类具有父类所有的特征和行为,继承的目的是找到类之间的共性,精简代码。

我们可以向一个已经存在的类中添加新的特性,而不必改变这个类。这个可以通过这个类派生一个新类来实现。这个新的类将具有原来的那个类的特性,以及新的特性。继承的魅力和强大在于它允许程序员利用已经存在的类,并且可以以某种方式修改这个类,而不会影响其他的东西。

构造函数的继承,使用call,apply方法

    function Person(name,age){
        this.name = name;
        this.age = age;
    }
    //Student继承于Person
    function Student(name,age,sex){
        //call方法
        Person.call(this,name,age);
        //apply方法(两种写法)
        Person.apply(this,arguments)
        Person.apply(this,[name,age]);
        this.sex = sex;
    }
    var stu = new Student("小明","18","男");
    console.log(stu);

原型的继承:因为创建的对象由构造函数和原型两部分的属性和行为组成,所以需要进行原型的继承。JavaScript中的数据几乎都是对象,存在一个根对象Object.prototype。

传值:简单数据类型之间的赋值为传值。

传址:复杂数据类型之间的赋值为传址。

    var a = 1;
    var b = a;
    b = 5;
    alert(a);
    //a将值直接复制给b,修改b的值并不会影响a。
    var arr1 = [1,2,3];
    var arr2 = arr1;
    arr2[0] = 10;
    alert(arr1[0]);
    //arr1将值的地址复制给arr2,修改arr2的值会影响到arr1的值。

因此,原型的继承应用以下方式:

    function Person(name){
        this.name = name;
    }
    Person.prototype.say = function(){
        alert("person");
    }
    function Student(name,age){
        Person.apply(this,arguments);
        this.age = age;
    }
    //创建一个空的构造函数
    function Lin(){};
    //通过赋值实现传址,Lin的原型就跟Person的一样了
    Lin.prototype = Person.prototype;
    //通过实例化出来的对象的存储地址就是新的地址了,同时赋值给Student实现了传址,所以Student.prototype的地址就是
    //实例化出来的对象的地址,则其的内容就跟被继承的原型的内容一致,实现了原型继承
    Student.prototype = new Lin();
    //再更改其constructor属性,达到跟创建原型完全一致
    Student.prototype.constructor = Student;
    var person = new Person("小明");
    var student = new Student("小红","18");
    student.say();

克隆

JSON.stringify():将[]或{}的对象转换成字符串形式的值。

JSON.parse():将字符串形式的[]或{}值转换成对象。

克隆实现原理:利用字符串赋值为传值的特点,先将对象转换成字符串形式,然后将字符串形式的值再转换成对象。

兼容问题:不支持低版本IE浏览器。

    function Person(name){
        this.name = name;
    }
    var person = new Person("小明");
    var str = JSON.stingify(person);
    var newObj = JSON.parse(str);
    newObj.name = "小红";
    console.log(person.name);
特征三:多态

多态指事物具有不同形式的能力。比如说加法操作,如果操作的是数字,则为两个数字求和;如果操作的是字符串,则将连接两个字符串。

多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着虽然针对不同对象的具体操作不同,但通过一个公共的类,那些操作可以通过相同的方式予以调用。多态在实现继承的过程中被广泛应用。

面向对象设计语言支持多态,术语称之为”one interface muliple method(一个接口,多个实现)”。简单来说,多态机制允许通过相同的接口引发一组相关但不相同的动作,通过这种方式,可以减少代码的复杂度。在某个特定的情况下应该做出怎样的动作,这由编译器决定,而不需要程序员手工干预。

typeof查看数据类型的改进

typeof可以准确判断出简单数据类型,但对复杂数据类型的判断相对比较模糊。例如:数组对象/时间对象/正则对象/Math对象等都返回的是“object”。因此封装一个函数来查询具体类型。

其原理为Object对象的prototype的toString()方法会返回一个表示对象本身类型的字符串,再通过截取即可。

    function type(obj){
        var o = {};
        var str = o.toString.call(obj).slice(8,-1).toLowerCase();
        return str;
    }
    var arr = [1,2,3];
    console.log(type(arr));

JavaScriptRegExp正则对象

RegExp对象

RegExp对象表示正则表达式,是对字符串执行模式匹配的强大工具。

构造正则表达式方式:

  1. 直接定义:var reg=/pattern/attributes;

  2. 创建RegExp对象:var reg=new RegExp(pattern,attributes);

参数pattern是一个字符串,指定了正则表达式的模式或其他正则表达式;

参数attribute是一个可选字符串,包含属性”g”、”i”和”m”,分别用于指定全局匹配、区分大小写的匹配和多行匹配。ECMAScript标准化之前,不支持m属性。如果pattern是正则表达式,而不是字符串,则必须省略该参数。

RegExpObject.test(string)

检测字符串是否匹配某个模式,是则返回true,否则返回false。

修饰符

正则检测方式,如果不设置全局检测,那么只要检测到一次就结束。

    i        不区分大小写

    g        全局匹配

    m        多行匹配

元字符

    .        查找单个字符,所有非换行和行结束符的字符

    \w        查找数字字母下划线

    \W        查找非数字字母下划线

    \d        查找数字

    \D        查找非数字

    \s        查找空格

    \S        查找非空格

    \b        检测单词开头或者结尾是否有

    \B        不处于单词开头或结尾的

    \0        空字符串,也相当于NUL

    \n        查找换行符

    \f        查找换页符

    \t        查找制表符

    \v        查找垂直制表符

    \xxx    查找以八进制数xxx规定的字符

    \xdd    查找以十六进制数dd规定的字符

    \uxxxx    查找以十六进制数xxxx规定的Unicode字符

量词

    n+        包含一个及以上(至少一个)n的字符串

    n*        包含零个或多个n的字符串

    n?        包含零个或一个n的字符串

    n{X}    包含X个n的序列的字符串

    n{X,Y}    包含X到Y个n的序列的字符串

    n{X,}    包含至少X个n的序列的字符串

    n$        匹配任何结尾为n的字符串

    ^n        匹配任何开头为n的字符串

    ?=n        匹配任何其后紧接指定字符串n的字符串

    ?!n        匹配任何其后没有紧接指定字符串n的字符串

方括号

    [abc]    查找方括号之间的任何字符

    [^abc]    查找任何不在方括号之间的字符

    [0-9]    查找任何从0至9的数字

    [a-z]    查找任何从小写a到小写z的字符

    [A-Z]    查找任何从大写A到大写Z的字符

    [A-Za-z]查找任何从大写A到小写Z的字符

    ()        查找任何指定的选项

支持正则表达式的方法

stringObject.search(regexp)

返回第一个与regexp相匹配的起始位置,如果没有则返回-1。此方法不支持全局匹配,如需忽略大小写,需添加i。

stringObject.match(regexp)

返回存放匹配结果的数组。数组内容依赖于regexp是否有全局标志g。

stringObject.replace(regexp,replacement)

返回一个新的字符串,用replacement替换regexp第一次匹配或所有匹配之后得到的。

stringObject.spilt(separator,howmany)

前面已讲过,在此不再一一赘述。

    //判断手机号
    var reg1=/^1[34578]\d{9}/;
    //判断固定电话号码
    var reg2=/(^0\d{2,3}-[1-9]\d{6,7}$)|(^[1-9]\d{6,7}$)/;
    //判断汉字
    var reg3=/[\u4e00-\u9fa5]+/g;

    //选择替换关键字
    var reg4=/哈哈|呵呵|这个是/g;
    var str="这个是的呵呵,这个哈哈是的,呵呵";
    var newStr=str.replace(reg4,function(sr){
        var str="";
        for(var i=0;i<sr.length;i++){
            str+="*";
        }
        return str;
    })
    console.log(newStr);

JavaScriptTouch事件、陀螺仪、加速度、cookie和localStorage

Touch事件

touch事件在用户触摸屏幕时触发。其与mouse事件的最大区别在于其支持多点触控。主要有以下几种:

touchstart:相当于mousedown事件

touchmove:相当于mousemove事件

touchend:相当于mouseup事件

应用如下:

    <style>
        .divtouch{
            width:300px;
            height:500px;
            border:1px solid blue;
            position:relative;
            margin:0 auto;
        }
        .divtouch p{
            font-size:30px;
            text-align:center;
        }
        .divtouch div{
            position:absolute;
            width:50px;
            height:50px;
            background-color:pink;
            top:0;
            left:0;
        }
    </style>
    <div class="divtouch">
        <p></p>
        <div></div>
    </div>
    <script>
        var para=document.querySelector(".divtouch p");
        var divtouchBlock=document.querySelector(".divtouch div");
        var s={
            startX:0,
            startY:0,
            endX:0,
            endY:0,
            disX:0,
            disY:0,
            ofl:0,
            oft:0,
        }
        divtouchBlock.addEventListener("touchstart",function(e){
            var e=e||window.event;
            para.innerHTML=e.touches.length+"根手指";
            s.ofl=divtouchBlock.offsetLeft;
            s.oft=divtouchBlock.offsetTop;
            s.startX=e.touches[0].clientX;
            s.startY=e.touches[0].clientY;
            e.preventDefault();
        },false)
        document.addEventListener("touchmove",function(e){
            var e=e||window.event;
            if(e.touches.length!=1){
                return;
            }
            s.endX=e.touches[0].clientX;
            s.endY=e.touches[0].clientY;
            s.disX=s.endX-s.startX+s.ofl;
            s.disY=s.endY-s.startY+s.oft;
            divtouchBlock.style.left=s.disX+"px";
            divtouchBlock.style.top=s.disY+"px";
        },false)
    </script>
    
    

设备事件——方向API(陀螺仪)

方向事件指DeviceOrientationEvent,其触发事件为deviceorientation

    if(window.DeviceOrientationEvent){
        window.addEventListener("deviceorientation",function(e){
            var e=e||window.event;
            e.alpha;//0~360度,0度指向正北方(Z轴)
            e.beta;//设备前后转-180~180度(X轴)
            e.gamma;//设备左右转-90~90度(Y轴)
        },false)
    }

设备事件——加速度API

加速度事件指DeviceMotionEvent,其触发事件为devicemotion

    if(window.DeviceMotionEvent){
        window.addEventListener("devicemotion",function(e){
            var e=e||window.event;
            e.acceleration.x;//加速度,x代表x方向
            e.acceleration.y;
            e.acceleration.z;

            e.accelerationIncludingGravity.x;//重力加速度,x轴代表x方向
            e.accelerationIncludingGravity.y;
            e.accelerationIncludingGravity.z;
        },false)
    }

cookie是存储于访问者的计算机中的变量。每当同一台计算机通过浏览器请求某个页面时,就会发送这个cookie。可以使用JavaScript来创建和取回cookie的值。

服务器环境下才能设置cookie,每一个域名下最多20个cookie,每一个cookie不超过4kb。

每个cookie都是一个名/值对,如果要一次存储多个名/值对,可以使用分号加空格(; )隔开。document.cookie="userId=123; userName=Jack";

cookie的名或值中不能使用分号(;)、逗号(,)、等号(=)及空格。如需存储用escape()函数进行编码,从而避免乱码出现。

    //设置cookie的名字,值,过期时间
    setCookie("usename/password",userVal,10);
    function setCookie(key,value,days){
        var newDate=new Date();
        var nowDay=nowDate.getDate();
        nowDate.setDate(nowDay+days);
        document.cookie=key+"="+value+";expires"+nowDate.toUTCString();
    }
    //删除cookie,将date设置为过去的时间来删除
    setCookie("name","",-1);

localStorageb本地存储

localStorage是HTML5提供的在客户端存储数据的新方法,localStorage是没有时间限制的数据存储

比cookie方便之处在于可以直接调用和删除。

    //设置localStorage
    localStorage.username=user.value;
    //获取localStorage
    alert(localStorage.username);
    //删除localStorage
    localStorage.removeItem("username");

可通过如下代码来对访问页面次数进行计数:

    <script>
        if(localStorage.pagecount){
            localStorage.pagecount=Number(localStorage.pagecount)+1;//localStorage.pagecount为自定义参数
        }else{
            localStorage.pagecount=1;
        }
        console.log(localStorage.pagecount);
    </script>

JavaScript滚轮事件的封装和滚轮轮播图

滚轮事件的封装

因鼠标滚动事件区分为火狐滚轮事件和非火狐滚轮事件,而且其向上滚动和向下滚动的正负值不同,因此封装滚轮事件以便调用。

    function mouseWheel(obj,fn){
        var isDown=true;
        var isFirefox=navigator.userAgent.search("Firefox")==-1?false:true;
        if(isFirefox){
            obj.addEventListener("DOMMouseScroll",wheel,false);
        }else{
            obj.onmousewheel=wheel;
        }

        function wheel(e){
            var e=e||window.event;
            if(isFirefox){
                isDown=e.detail>0?true:false;
            }else{
                isDown=e.wheelDelta>0?false:true;
            }
            fn.call(obj,e,isDown);
        }
    }

滚轮轮播图

通过利用上图的滚轮事件的封装函数,来设置轮播图的纵向滚动。

    <style>
        .wheelSlide{
            width:800px;
            height:500px;
            position:relative;
            overflow:hidden;
            border:1px solid gold;
            margin:0 auto;        
        }
        .wheelSlides{
            width:800px;
            height:2500px;
            position:absolute;
            top:0;
            left:0;
            transition-duration:3s;
        }
        .wheelSlides div{
            width:800px;
            height:500px;
            line-height:500px;
            text-align:center;
            font-size:100px;
            color:white;
        }
        .wheelSlides div:nth-child(1){
            background:paleturquoise;
        }
        .wheelSlides div:nth-child(2){
            background:lightpink;
        }
        .wheelSlides div:nth-child(3){
            background:palegreen;
        }
        .wheelSlides div:nth-child(4){
            background:peachpuff;
        }
        .wheelSlides div:nth-child(5){
            background:plum;
        }
    </style>
    <div class="wheelSlide">
        <div class="wheelSlides">
            <div>1</div>
            <div>2</div>
            <div>3</div>
            <div>4</div>
            <div>5</div>
        </div>
    </div>
    <script>
        var wheelSlide=document.querySelector(".wheelSlide");
        var wheelSlides=document.querySelector(".wheelSlides");
        var wheelSlidesDiv=document.querySelectorAll(".wheelSlides div");
        var s={
            isAct:false,
            index:0,
        }

        mouseWheel(wheelSlide,function(e,isDown){
            if(s.isAct){
                return;
            }
            s.isAct=!s.isAct;
            setTimeout(function(){
                s.isAct=!s.isAct;
            },3000)
            if(isDown){
                s.index++;
                s.index=s.index>wheelSlidesDiv.length-1?wheelSlidesDiv.length-1:s.index;
            }else{
                s.index--;
                s.index=s.index<0?0:s.index;
            }
            wheelSlides.style.top=-s.index*500+"px";
            e.preventDefault();
        })

        function mouseWheel(obj,fn){
            var isDown=true;
            var isFirefox=navigator.userAgent.search("Firefox")==-1?false:true;
            if(isFirefox){
                obj.addEventListener("DOMMouseScroll",wheel,false);
            }else{
                obj.onmousewheel=wheel;
            }

            function wheel(e){
                var e=e||window.event;
                if(isFirefox){
                    isDown=e.detail>0?true:false;
                }else{
                    isDown=e.wheelDelta>0?false:true;
                }
                fn.call(obj,e,isDown);
            }
        }
    </script>
    
    
1
2
3
4
5

JavaScriptCallback回调函数和事件委托的封装

callback回调函数

由于JavaScript语句是按照次序执行的,因为动画未完成,动画之后的语句可能会产生错误或页面冲突。为避免这种情况,可以使用callback函数。

callback回调函数就是放在另一个函数(parent)的参数列表中,作为参数传递给parent,然后在parent函数体的某个位置执行。

    function fn(a,b,fn2){
        console.log(a+b);
        fn2();
    }
    function callBack(){
        console.log("我是函数参数")
    }
    fn(a,b,callBack);//在这里就callBack就是回调函数

事件委托的封装

    function targetHandle(type,child,parent,fn){
        //type事件类型 child
        if(parent.addEventListener){//判断浏览器是否为IE浏览器,此处为非IE
            parent.addEventListener(type,function(e){
                var e=e||window.event;
                var target=e.target;
                //事件想绑定到child上
                for(var i=0;i<child.length;i++){
                    //判断触发事件的元素是否是想绑定事件的元素或者是想绑定元素事件的子代
                    if(cp(target,child[i])){
                        fn.call(child[i]);//改变this指向,否则指向window
                    }
                }
            },false)
        }else{
            parent.attachEvent(type,function(e){
                var e=e||window.event;
                var target=e.target;
                for(var i=0;i<child.lenthli++){
                    if(cp(target,child[i])){
                        fn.call(child[i]);
                    }
                }
            })
        }
    }

    function cp(child,parent){
        if(child==parent){
            return true;
        }else{
            while(child.parentNode){
                if(child.parentNode==parent){
                    return true;
                    break;
                }else{
                    child=child.parentNode;
                }
            }
        }
    }

    例如:
    var wrap=document.querySelector("ul");
    var lis=wrap.getElementsByTagName("li");
    targetHandle("click",lis,wrap,function(){
        console.log(this);
    })