『笔记』『教程』搭建FRP内网穿透，轻松实现外网访问群晖
前言内网穿透frp穿透教程来了，不多bb直接上教程，想了解frp具体原理和详情的请百度搜索名，这里最终演示的目的是通过frp登陆群晖。 本教程适用于一下人群：没有公网想进行外网访问nas的有公网在公网出问题增加一个外网访问保障的{alert type="success"}友情提示，如果对linux或者命令不怎么熟悉的，就完全按照我的教程做（本教程已经尽力最简化了），我这里怎么操作，你就怎么操作，先保证成功，然后在根据自身个性化设置。{/alert}一、服务端操作（一）前提条件SSH工具：FinalShell 下载地址一台具有公网ip的云服务器（二）设置服务器root密码和ssh1、 首先登陆腾讯云，修改服务器root密码（知道的话可以不修改）2、用ssh工具登陆云服务器。（三）安装frps1、因为frps官方安装需要vi编辑器和linux等命令，这里为了简便，采用github上开源的一键脚本安装frps，脚本有两个源，国外VPS用Github的源，国内的VPS建议使用Aliyun的源，要不可能很慢。Aliyun（阿里云源） #下载脚本（依次复制输入） wget https://code.aliyun.com/MvsCode/frps-onekey/raw/master/install-frps.sh -O ./install-frps.sh #设置脚本权限 chmod 700 ./install-frps.sh #运行脚本 ./install-frps.sh install2、本教程使用的是腾讯云国内服务器，使用Aliyun的源，依次输入命令，如下图。3、输入第三条命令以后回车进入配置界面，选择下载frps的下载地址，这里面我们选择【1】。下面的一些端口号及配置请根据自身选择输入，不要完全按照我的照搬，如果不明白端口的意思就按照我的输入，在教程完成之后，明白了端口的意义，在根据自身需求修改。（尤其标记重要的请一定要修改）4、输入frps的通信端口，请根据自己需求输入，我这里输入【7000】5、输入http通信端口，我这里输入【8880】（重要）6、输入https通信端口，我这里输入【8443】（重要）7、输入frp信息面板端口，我这里输入【8444】8、分别输入管理面板用户名和密码，例如用户名为admin，管理密码为admin。9、输入通信密码，我这里输入去、12345678（重要）10、设置域名，如果有就填写，没有就默认IP，这里我选择默认。11、接下来的步骤一路默认敲击回车就行 12、出现这个界面核对之前输入的信息是否正确，然后继续下一步。13、稍等片刻，会出现如下界面。14、登陆腾讯云控制台找到【防火墙设置】开放4、5、6、7步骤的端口，这里我开放【7000】【8880】【8443【8444】】端口。（多个端口请用英文输入状态下的,隔开）15、 浏览器输入域名（ip）:端口号，如果出现下面网页说明后台搭建成功，这里我输入 http://152.136.119.20:8444 用户名和密码为步骤8设置。服务器端成功部署完成，总体来说使用一键脚本部署还是非常简单的，感谢一键脚本的开发作者。群辉客户端1、登录群辉，打开file station在docker目录下新建frp文件夹，在桌面新建立一个文本文档，然后将文本文档拖动到frp目录中。2、 双击文本文档，粘贴下如下命令，请根据自己情况灵活改变配置，这里举两个例子，一个是使用http协议访问NAS，一个是使用tcp协议登录ssh，然后ctrl+s保存，将文件重命名为frpc.ini。[common] # 服务器ip server_addr = 152.136.119.20 token = 12345678 # 端口 server_port = 7000 #名字,自定义 [nas] # 类型 type = tcp # 局域网内设备ip local_ip = 192.168.31.11 # 局域网内设备端口 local_port = 5000 # 监听端口*可以修改为任意字母，等号后面的数字 remote_port = 5002 #名字,自定义 [ssh] # 类型 ssh类型为tcp type = tcp # 局域网内设备ip local_ip = 192.168.31.11 # 局域网内设备端口 local_port = 22 # 监听端口*可以修改为任意字母，等号后面的数字注意：所有监听端口都需要在服务区防火墙中开放。 3、 打开群辉docker→注册表搜索'stilleshan'选择stilleshan-frpc下载镜像,下载好以后再镜像中启动。4、 下载完成以后启动映像，容器名称默认，勾选使用高级权限执行容器，然后点击高级设置。5、 按照下面设置。 高级设置：勾选启用自动重新启动 存储空间：建立如下链接映射路径为：/frp/frpc.ini网络：勾选与docker host相同的网络端口设置、链接、环境保持默认设置不用修改6、按照第5步配置完成以后，容器成功启动，如下图。7、这时候我们在浏览器中输入（域名）服务器ip:端口号即可以成功在外网访问。 域名方式：http://152.136.119.20:5002
『笔记』『教程』自制随机显示必应每日一图，以及API代码及调用方法
前言主题有好多模板设置了分类的背景图，调用了第三方api但是最近第三方挂了这就是图省事不写代码的后果，一旦图片都失效，网站打开速度慢不说，图片的背景图还是灰蒙蒙一片，非常尴尬。。。百度了下必应每日api源代码有很多，但是随机显示的也都是调用人家自己的，这样就可能再次出现无法打开的情况，但是仅仅调用一张图片又略显单调（最烦我这种啥也不是，要求还多的人。。。）终于皇天不负有心人让我找到了一个随机显示必应图片的api调用方法，附上代码及适用教程。调用方法(教程和代码在下方)此API只支持https调用，所有参数均仅适用于以 GET 方式进行请求，可直接插入img标签中请求地址：（不要适用本站api代码，跨域）https://www.hellolin.cn/api-hello/bing调用参数参数代码参数含义可用参数rand是否随机显示最近8天内的图片true or falseday显示指定的最近图片-1，0，1，2，3，4，5，6，7(0为今天，-1为昨天)size指定获取图片大小详见下方可用分辨率info获取图片基础信息（json格式）true or false以上所有参数均非必要，默认参数为rand=false，day=0，size=1920×1080，info=false可用分辨率1920x10801366x7681280x7681024x768800x600调用示例默认调用：https://www.hellolin.cn/api-hello/bing不带任何参数调用，显示必应当天图片。Info调用：https://www.hellolin.cn/api-hello/bing?info=true返回值：{ title:Micheldever Wood的蓝铃花，英国汉普郡 (© Hursley/Getty Images Plus), url:https://www.bing.com/th?id=OHR.BluebellWood_ZH-CN8128422960_1920x1080.jpg, link:https://www.bing.com/search?q=%E8%93%9D%E9%93%83%E8%8A%B1&form=hpcapt&mkt=zh-cn, time:20200419 }随机调用:(随机显示一张图片)https://www.hellolin.cn/api-hello/bing?rand=true {mtitle title="随机显示，刷新更换"/}教程和API代码{hide}首先在网站根目录新建一个php文件，例如：index.php，然后粘贴如下代码：<?php //判断是否随机调用 if ($_GET['rand']==='true') { $gettime = rand(-1,7); }else{ //若不为随机调用则判断是否指定日期 $gettimebase = $_GET['day']; if (empty($gettimebase)) { $gettime = 0; }else{ $gettime = $gettimebase; } } //获取Bing Json信息 $json_string = file_get_contents('https://www.bing.com/HPImageArchive.aspx?format=js&idx='.$gettime.'&n=1'); //转换为PHP数组 $data = json_decode($json_string); //提取基础url $imgurlbase = "https://www.bing.com".$data->{"images"}[0]->{"urlbase"}; //判断是否指定图片大小 $imgsizebase = $_GET['size']; if (empty($imgsizebase)){ $imgsize = "1920x1080"; }else{ $imgsize = $imgsizebase; } //建立完整url $imgurl = $imgurlbase."_".$imgsize.".jpg"; //获取其他信息 $imgtime = $data->{"images"}[0]->{"startdate"}; $imgtitle = $data->{"images"}[0]->{"copyright"}; $imglink = $data->{"images"}[0]->{"copyrightlink"}; //判断是否只获取图片信息 if ($_GET['info']==='true') { echo "{title:".$imgtitle.",url:".$imgurl.",link:".$imglink.",time:".$imgtime."}"; }else{ //若不是则跳转url header("Location: $imgurl"); }{/hide}结语保存文件，最后打开网页查看效果，如果有不同需求网址后面加“?参数代码=true(或者false)”，参考上面的参数表格完整代码就是（以随机为例）： https://网址/index.php?rand=true 酱婶儿的就OK啦，把这个链接放在主题模板的背景图接口就大功告成！
『原创』『教程』为你的博客添加阅读模式（适配Joe，其他主题也可用）
『原创』『教程』给自己博客的侧栏增加社交信息，方便业务（PY）联系
前言前不久突发奇想，录了一个视频然后留了自己的博客，却发现博客却没有链接回去的方式，所以就写了一个社交信息的侧栏模块然后有小伙伴看到了，专门留言让我出个教程，当时答应的好好的，可是一连鸽了好几天，今天进入留言板看到许诺的话，不禁老脸一红，差点忘了这茬了 ::(狂汗) 成果展示博客的侧栏增加社交信息2.0 这个模块适合任何主题及程序，只需要根据自己的主题或者程序进行改进就行我这里演示的是我正在使用的Joe主题，是一款轻量、开源的主题{tabs}{tabs-pane label="PC展示"}{/tabs-pane}{tabs-pane label="PE展示"}{/tabs-pane}{/tabs}教程开始一、添加PC端打开 Joe/public/aside.php 文件，然后在想要增加的位置添加以下代码{tabs}{tabs-pane label="代码"}{hide} <?php if ($this->options->SocialInfo && (($this->options->SocialSwitch === 'on') || ($this->options->SocialSwitch === 'on2'))) : ?> <?php $SocialInfo = $this->options->SocialInfo; if ($SocialInfo) { $SocialInfo_arr = explode("\r\n", $SocialInfo); if (count($SocialInfo_arr) > 0) { for ($i = 0; $i < count($SocialInfo_arr); $i++) { $QQ = explode("||", $SocialInfo_arr[$i])[0]; $WeChat = explode("||", $SocialInfo_arr[$i])[1]; $BiliBili = explode("||", $SocialInfo_arr[$i])[2]; $Weibo = explode("||", $SocialInfo_arr[$i])[3]; } } } ?> <a href="https://wpa.qq.com/msgrd?v=3&uin=<?php echo trim($QQ) ?>&site=qq&menu=yes" target="_blank" title="QQ"> <img src="<?php echo trim($WeChat) ?>" /> <a href="https://space.bilibili.com/<?php echo trim($BiliBili) ?>" target="_blank" title="哔哩哔哩"> <a href="https://weibo.com/u/<?php echo trim($Weibo) ?>" target="_blank" title="微博"> <?php endif; ?>{/hide}{/tabs-pane}{tabs-pane label="位置"}{/tabs-pane}{/tabs}二、添加PE端打开 Joe/public/header.php 文件，然后在想要增加的位置添加上面PC的代码PE端的代码和上面的一样，只需要将 换成 三、添加后台直接在 Joe/functions.php 添加以下代码（当然，如果看过我之前的文章，也可以放在 Joe/public/custom.php 里面）// 侧栏社交信息开关 $SocialSwitch = new Typecho_Widget_Helper_Form_Element_Select( 'SocialSwitch', array( 'off' => '关闭（默认）', 'on' => '开启PC社交信息', 'on1' => '开启PE社交信息', 'on2' => '同时开启PC与PE社交信息', ), 'off', '是否启用侧栏社交信息', '介绍：开启后，侧栏展示社交信息功能（必须填写下面的侧栏社交信息）' ); $SocialSwitch->setAttribute('class', 'joe_content joe_custom'); //没有custom.php就把joe_custom改成joe_other $form->addInput($SocialSwitch->multiMode()); //侧栏社交信息 $SocialInfo = new Typecho_Widget_Helper_Form_Element_Textarea( 'SocialInfo', NULL, NULL, '侧栏社交信息', '介绍：用于设置侧栏社交信息 格式：你的QQ号 || 你的微信二维码链接 || 你的B站ID || 你的微博ID 例如：123456 || https://www.a.con/a.png || 13503064 || 3125196513 ' ); $SocialInfo->setAttribute('class', 'joe_content joe_custom'); //没有custom.php就把joe_custom改成joe_other $form->addInput($SocialInfo);然后你网站后台主题就会出现这样两项，根据相应的格式把你的信息填进去就行了四、添加显示样式在 Joe/assets/css/joe.global.min.css 里添加以下样式我这里的样式是已经压缩了的，如果想要自己修改，只需要在代码编辑器里格式化以下就行了.top-social{position:relative;padding:10px 0;width:250px;display:flex;flex-wrap:wrap;background:var(--background);justify-content:space-around;margin-bottom:15px;border-radius:var(--radius-wrap);box-shadow:var(--box-shadow)}.top-social li{width:50px;text-align:center;padding:5px 0px}.top-social li img{height:25px}.top-social .wechat{position:relative}.top-social .wechat .wechatInner{display:none;position:absolute;box-shadow:0px 1px 4px 2px var(--theme);border-radius:var(--radius-wrap);transition:.7s all ease;background:var(--background);-webkit-transition:.7s all ease;top:-175px;left:-45px;transform:translate3d(0, 16px, 0);width:140px;height:140px}.top-social .wechat .wechatInner::before{content:"";position:absolute;bottom:-16px;left:0;right:0;margin:auto;display:inline-block;width:0px;border:18px solid transparent;border-bottom:none;border-top-color:#fff;filter:drop-shadow(0px 4px 2px var(--theme))}.top-social .wechat .wechatInner img{border-radius:var(--radius-wrap);width:140px;height:auto;padding:0;background:none}.top-social .wechat:hover .wechatInner{display:block}.pe-social{width:100%}结语教程到此就结束了，其实还是很简单的不过我又想把这个模块做成填写ico图片链接和跳转链接的自定义模块，就可以自由添加更多的社交信息但是那样只能舍弃微信那个移入弹窗的效果，所以很难取舍呀{timeline}{timeline-item color="#19be6b"}2022.3.16 在这里挖一个坑吧：利用JS选择对应的元素，实现微信的弹窗效果（令人头秃 :@(哭泣) ）{/timeline-item}{timeline-item color="#ed4014"}2022.3.19 Flag已实现，请移步 侧栏社交信息2.0 {/timeline-item}{/timeline}
数据类型1、分类基本（值）类型{alert type="info"}String：任意字符串Number：任意的数字Boolean：true/falseundefined：undefinednull ：null{/alert}对象（引用）类型{alert type="info"}object ：任意对象function ：函数，一种特别的对象（可以执行）array ：数组，一种特别的对象（数值具有下标，内部数据是有序的）{/alert}2、类型的判断{alert type="success"}typeof ：可以判断 undefined/ 数值 / 字符串 / 布尔值Boolean / Function -不能判断 null和object object和arrayinstanceof ：判断对象的具体类型=== ：全等，可以判断undefined,null{/alert} 1、undefined与null的区别？undefined 代表定义未赋值null 代表定义并赋值了，但是值为null2、什么时候给变量赋值为null？初始赋值：表明将要赋值为对象结束前：让对象成为垃圾对象（垃圾回收）3、严格区别变量类型与数据类型？（1）数据的类型基本类型对象类型（2）变量的类型（变量内存值的类型）基本类型：保存的基本类型的数据引用类型：保存的是地址值对象类型即是引用类型 数据、变量、内存定义1、什么是数据存储在内存中代表特点信息的东西，本质上是0101.......数据的特点：可传递、可运算2、什么是内存内存条通电以后产生的可存储数据的空间（临时的）内存产生和死亡： 内存条（电路板）==>通电==>产生内存空间==>存储数据==>处理数据==>断电==>内存空间和数据都消失一块小内存的2个数据 `内部存储的数据` `地址值`内存分类 `栈：保存全局变量/局部变量（变量名）` `堆：对象（函数、数组）` 3、什么是变量可变化的量：由变量名、变量值组成每个变量都对应一块小内存，变量名用来查找对应的内存，变量值就是内存中保存的数据4、内存、数据、变量三者之间的关系内存是用来存储数据的空间变量是内存的标识
DOM（文本对象模型）（20）鼠标拖拽的事件拖拽(一、二) 我是一段文字 box的偏移量=鼠标的偏移量-元素的偏移量捕获测试 按钮01 按钮02 拖拽（三） 我是一段文字 <img src="https://cdn.jsdelivr.net/gh/aill66/cdn@latest/usr/uploads/2021/08/809131067.png" id="img1" style="width:100px; position:absolute;" （21）滚轮的事件 （22）键盘的事件 键盘移动vid {nextPage/}BOM（浏览器对象模型）BOM可以通过JS来操作浏览器在BOM中提供了一组对象，用来完成对浏览器的操作BOM对象{alert type="success"}Window 代表的是整个浏览器的窗口，同时也是网页中的全局对象Navigator 代表当前浏览器的信息，通过该对象可以识别不同的浏览器Location 代表当前浏览器的地址栏信息，通过location可以获取地址栏信息或者操作浏览器跳转页面History 代表浏览器的历史记录，可以通过该对象来操作浏览器的历史记录由于隐私原因，该对象不能获取到具体的历史记录，只能操作浏览器向前或向后翻页，而且该操作只在当次访问有效Screen 代表用户的屏幕信息，通过该对象可以获取到用户的显示器的相关信息这些BOM对象在浏览器中都是作为window对象的属性保存的{/alert}// console.log(window.navigator); console.log(navigator); console.log(location); console.log(history);一、Navigator（浏览器信息）代表当前浏览器的信息，通过该对象可以识别不同的浏览器由于历史原因（网景公司倒闭了），Navigator对象中的大部分属性都已经不能识别浏览器了一般只会使用userAgent来判断浏览器的信息userAgent是一个字符串，这个字符串包含有用来描述浏览器信息的内容，不同的浏览器会有不同的userAgent// appCodeName 返回浏览器名称的代码 // appName 返回浏览器的名称 // userAgent 返回一个字符串来描述浏览器的信息 // alert(navigator.appName); // 在IE11中已经将微软和IE相关的标识都去除了，所以基本不能通过userAgent来识别浏览器是不是IE了 var ua = navigator.userAgent; console.log(ua); if(/firefox/i.test(ua)){ alert("我是火狐"); }else if(/chrome/i.test(ua)){ alert("我是Chrome"); }else if(/msie/i.test(ua)){ alert("我是IE浏览器"); }else if("ActiveXObject" in window){ alert("你是IE11，我已经抓住你了"); } // 如果不能通过userAgent来判断浏览器信息，还可以通过一些浏览器中特有的对象来判断浏览器的信息 // 比如：ActiveXObject // alert("ActiveXObject" in window); if("ActiveXObject" in window){ alert("你是IE，我已经抓住你了"); }else{ alert("你不是IE"); } 二、History（历史记录）代表浏览器的历史记录，可以通过该对象来操作浏览器向前或向后翻页 点我一下 History 去下一个页面 三、Location（浏览器地址栏）该对象中封装了浏览器的地址栏的信息 点我一下 四、Window（浏览器的窗口）window的方法1、 定时调用 （1）切换图片练习 开始 停止 （2）修改div移动练习 2、 延时调用 （1）定时器的应用一 点击按钮以后box1向右移动 {nextPage/}（2）定时器的应用二 点击按钮以后box1向右移动 点击按钮以后box1向左移动 （3）定时器的应用三 点击按钮以后box1向右移动 点击按钮以后box1向左移动 点击按钮以后box2向右移动 测试按钮 tools.js（用于存放工具程序） // 尝试创建一个可以执行简单动画的函数 // 参数:obj:要执行动画的对象 // attr:要执行动画的样式，比如left height top // target:执行动画的目标位置 // speed:移动的速度（正数向右移动，负数向左移动） // callback:回调函数，将会在动画执行完毕以后执行 function move(obj,attr,target,speed,callback){ // 关闭上一个定时器 clearInterval(obj.timer); // 获取box1目前的位置 var current = parseInt(getStyle(obj,attr)); // 判断速度speed的正负值 // 如果从0向800移动则speed为正，如果从800向0移动则speed为负 if(current > target){ // 此时速度应为负值 speed = -speed; } // 开启一个定时器用来执行动画效果 // 向执行动画的对象中添加一个timer属性，用来保存它自己的定时器的标识 obj.timer = setInterval(function(){ // 获取box1原来的left值 var oldValue = parseInt(getStyle(obj,attr)); // 在旧值的基础上增加,给box添加移动速度 var newValue = oldValue + speed; // 向左移动时需要判断newValue是否小于target // 向右移动时需要判断newValue是否大于于target if((speed < 0 && newValue < target) || (speed > 0 && newValue > target)){ newValue = target; } // 将新值设置给obj obj.style[attr] = newValue + "px"; // 当box1移动到了0px时，使其停止执行动画 if(newValue == target){ // 达到目标关闭定时器 clearInterval(obj.timer); // 动画执行完毕，调用回调函数 callback && callback(); } },30); }; /* 定义一个函数，用来获取指定元素的当前的样式 * 参数： * obj 要获取样式的元素 * name 要获取的样式名*/ function getStyle(obj,name){ if(window.getComputedStyle){ //正常浏览器的方式，具有getComputedStyle()方法 return getComputedStyle(obj,null)[name]; }else{ //IE8的方式，没有getComputedStyle()方法 return obj.currentStyle[name]; } };{nextPage/}3、 轮播图的改进 {nextPage/}4、类的操作 点击按钮修改box的样式 tools.js（工具函数）// 尝试创建一个可以执行简单动画的函数 // 参数:obj:要执行动画的对象 // attr:要执行动画的样式，比如left height top // target:执行动画的目标位置 // speed:移动的速度（正数向右移动，负数向左移动） // callback:回调函数，将会在动画执行完毕以后执行 function move(obj, attr, target, speed, callback) { // 关闭上一个定时器 clearInterval(obj.timer); // 获取box1目前的位置 var current = parseInt(getStyle(obj, attr)); // 判断速度speed的正负值 // 如果从0向800移动则speed为正，如果从800向0移动则speed为负 if (current > target) { // 此时速度应为负值 speed = -speed; } // 开启一个定时器用来执行动画效果 // 向执行动画的对象中添加一个timer属性，用来保存它自己的定时器的标识 obj.timer = setInterval(function () { // 获取box1原来的left值 var oldValue = parseInt(getStyle(obj, attr)); // 在旧值的基础上增加,给box添加移动速度 var newValue = oldValue + speed; // 向左移动时需要判断newValue是否小于target // 向右移动时需要判断newValue是否大于于target if ((speed < 0 && newValue < target) || (speed > 0 && newValue > target)) { newValue = target; } // 将新值设置给obj obj.style[attr] = newValue + "px"; // 当box1移动到了0px时，使其停止执行动画 if (newValue == target) { // 达到目标关闭定时器 clearInterval(obj.timer); // 动画执行完毕，调用回调函数 callback && callback(); } }, 30); }; /* 定义一个函数，用来获取指定元素的当前的样式 * 参数： * obj 要获取样式的元素 * name 要获取的样式名*/ function getStyle(obj, name) { if (window.getComputedStyle) { //正常浏览器的方式，具有getComputedStyle()方法 return getComputedStyle(obj, null)[name]; } else { //IE8的方式，没有getComputedStyle()方法 return obj.currentStyle[name]; } }; // 定义一个函数来向一个元素添加指定的class属性值 /*参数： obj 要添加class属性的元素 cn 要添加的class值*/ function addClass(obj, cn) { // 检查obj中是否含有cn if (!hasClass(obj, cn)) { // 如果没有cn则添加cn（添加一个空格防止直接拼串） obj.className += " " + cn; } }; // 判断一个元素中是否含有指定的class属性值 /*参数 obj 要添加class属性的元素 cn 要添加的class值 如果有该class值则返回true，否则返回false*/ function hasClass(obj, cn) { // 判断obj中是否有cn这个class值 // 创建一个正则表达式 // var reg = /\bb2\b/; var reg = new RegExp("\\b" + cn + "\\b"); return reg.test(obj.className); }; // 删除一个元素中指定的class属性 function removeClass(obj, cn) { // 创建一个正则表达式 var reg = new RegExp("\\b" + cn + "\\b"); // 删除class obj.className = obj.className.replace(reg, ""); }; // toggleClass用来切换一个类 // 如果元素中有指定类则删除，没有则添加 function toggleClass(obj, cn) { // 判断obj中是否含有cn if (hasClass(obj, cn)) { // 有则删除 removeClass(obj, cn); } else { // 没有则添加 addClass(obj, cn); } };5、二级菜单完善 二级菜单 在线工具 图像优化 收藏夹图标生成器 邮件 梯度图像 按钮生成器 支持我们 图像优化 收藏夹图标生成器 邮件 梯度图像 按钮生成器 合作伙伴 图像优化 邮件 梯度图像 按钮生成器 支持我们 图像优化 邮件 梯度图像 按钮生成器 二级菜单动画过渡 二级菜单 在线工具 图像优化 收藏夹图标生成器 邮件 梯度图像 按钮生成器 支持我们 图像优化 收藏夹图标生成器 邮件 梯度图像 按钮生成器 合作伙伴 图像优化 邮件 梯度图像 按钮生成器 支持我们 图像优化 邮件 梯度图像 按钮生成器 五、JSON JSON的兼容性
DOM（文档对象模型）1、DOM的简介（1）什么是DOM：DOM：文档对象模型（Document Object Model） （2）模型：（3）节点：节点的类型节点的属性例： 我是一个按钮 （4）事件（Event）事件：就是用户和浏览器之间的交互行为可以在事件对应的属性中设置一些js代码，当事件被触发时，这些代码将会执行onclick 点击一次、ondblclick点击两次可以为按钮的对应事件绑定处理函数的形式来响应事件，这样当事件被触发时，其对应的函数将会被调用 我是一个按钮 （5）文档的加载浏览器在加载一个页面时，是按照自上向下的顺序加载的，读取到一行就运行一行将js代码编写到页面的下部是为了可以在页面加载完毕后再执行js代码onload事件会在整个页面加载完毕后才触发可以为window绑定一个onload事件，可以确保代码执行时所有的DOM对象都已经加载完毕了 点我一下 2、DOM查询（1）获取元素节点window.onload = function(){ //为id为btn01的按钮绑定一个单击响应函数 var btn01 = document.getElementById("btn01"); btn01.onclick = function(){ var bj = document.getElenmentById("bj"); //打印bj //innerHTML 通过这个属性可以获取到元素内部的html代码 alert(bj.innerHTML); }; //为id为btn01的按钮绑定一个单击响应函数 var btn02 = document.getElementById("btn02"); btn02.onclick = function(){ //查找所以li节点 //getElementsByTagName()可以根据标签名来获取一组元素节点对象 //这个方法会返回一个类数组对象，所有查询到的元素都会封装到对象中 //即使查询到的元素只有一个也会封装到一个对象中 var lis = document.getElenmentsByTagName("li"); //打印lis //alert(lis); //变量lis for(var i=0; i<lis.length; i++){ alert(lis[i].innerHTML); } }; //为id为btn03的按钮绑定一个单击响应函数 var btn03 = document.getElementById("btn03"); btn03.onclick = function(){ //查找name=gender的所有节点 var inputs = document.getElenmentsByNmae("gender"); //alert(inputs.length); for(var i=0; i<inputs.length; i++){ //对于自结束标签，innerHTML无效 //alert(inputs[i].innerHTML); //如果需要读取元素节点属性直接使用：元素.属性名 //class属性不能采用这种方式，读取class属性时需要使用：元素.className alert(inputs[i].value); alert(inputs[i].name); alert(inputs[i].className); } }; };（2）图片切换的练习 <mata charset="UTF-8"> 上一张 下一张 （3）获取元素节点的子节点window.onload = function(){ //为id为btn04的按钮绑定一个单击响应函数 var btn04 = document.getElementById("btn04"); btn04.onclick = function(){ //获取id为city的元素 var city = document.getElementById("city"); //查找#city下所有的li节点 var lis = city.getElementsByTagName("li"); for(var i=0; i<lis.length; i++){ alert(lis[i].innerHTML); } }; //为id为btn05的按钮绑定一个单击响应函数 var btn05 = document.getElementById("btn05"); btn05.onclick = function(){ //返回id为city的节点 var city = document.getElementById("city"); //返回#city下所有子节点 //childNodes属性会获取包括文本节点在内的所有节点 //根据DOM标准，标签与标签之间的空白也会当成文本节点 //但是IE8及以下的浏览器，不会将空白文本当成子节点 var cns = city.childNodes; //alert(cns.length); // for(var i=0; i<cns.length; i++){ // alert(cns[i]); // } //children属性可以获取当前元素的所有子元素 var cns2 = city.chileren; alert(cns2.length); }; //为id为btn06的按钮绑定一个单击响应函数 var btn06 = document.getElementById("btn06"); btn06.onclick = function(){ //获取id为phone的元素 var phone = document.getElementById("phone"); //返回#phone的第一个子节点 //phone.childNodes[0]; //firstChild属性可获取到当前元素的第一个子节点（包括空白文本节点） var fir = phone.firstChild; //firstElementChild属性可以获取当前元素的第一个子元素，IE8及以下不支持 // fir = phone.firstElementChild; alert(fir.innerHTML); }; };（4）获取元素节点的父节点和兄弟节点//定义一个函数，专门为指定的元素绑定单击函数 /* 参数 idStr 要绑定单击响应函数的对象的id属性值 fun 事件的回调函数，当单击元素时，该函数将会被触发 */ function myClick(idStr,fun){ var btn = document.getElementById("idStr"); btn.onclick = fun; }; window.onload = function(){ //为id为btn07的按钮绑定一个单击响应函数 myClick("btn07",function(){ // 获取id为bj的节点 var bj = document.getElementById("bj"); // 返回#bj的父节点 var pn = bj.parentNode; // alert(pn.innerHTML); // innerText 该属性可以获取到元素内部的文本内容，会去除html标签 alert(pn.innerText); }); //为id为btn08的按钮绑定一个单击响应函数 myClick("btn08",function(){ // 获取id为Android的元素 var and = document.getElementById("android"); //返回id为Andrid的前一个兄弟元素(也可能获取到空白文本) var ps = and.previousSibling; // 获取前一个元素兄弟（不包含空白文本），IE8以下不支持 var pe = and.previousElementSibling alert(ps.innerHTML); alert(pe.innerHTML); }); // 读取#username的value属性值 myClick(btn09,function(){ // 获取id为username的元素 var um = document.getElementById("username"); // 读取um的value属性值 // 文本框的value属性值，就是文本框中填写的内容 alert(um.value); }); // 读取#username的value属性值 myClick(btn10,function(){ // 获取id为username的元素 var um = document.getElementById("username"); // 设置um的value属性值 um.value = "今天天气真不错"; }); // 返回#bj的文本值 myClick(btn11,function(){ // 获取id为bj的元素 var bj = document.getElementById("bj"); // alert(bj.innerHTML); // alert(bj.innerText); // 获取bj中的文本 // var fc = bj.firstChild; // alert(fc.nodeValue); // 与上面相同 alert(bj.firstChild.nodeValue); }); };{nextPage/}（5）全选练习 全选练习 你爱好的运动是？ 全选/全不选 足球 篮球 羽毛球 乒乓球 （6）DOM查询的其他方法 我是box1中的div 我是box1中的div 我是box1中的div 我是box1中的div （7）DOM增删改 Untitled Document 你喜欢哪个城市? 北京 上海 东京 首尔 创建一个"广州"节点,添加到#city下 将"广州"节点插入到#bj前面 使用"广州"节点替换#bj节点 删除#bj节点 读取#city内的HTML代码 设置#bj内的HTML代码 创建一个"广州"节点,添加到#city下 （8）添加删除记录-删除 添加删除记录练习 Name Email Salary Tom tom@tom.com 5000 Delete Jerry jerry@sohu.com 8000 Delete Bob bob@tom.com 10000 Delete 添加新员工 name: <input type="text" name="enmName" id="empName" email: <input type="text" name="email" id="email" salary: <input type="text" name="salary" id="salary" Submit {nextPage/}（9）添加删除记录-添加 添加删除记录练习 Name Email Salary Tom tom@tom.com 5000 Delete Jerry jerry@sohu.com 8000 Delete Bob bob@tom.com 10000 Delete 添加新员工 name: <input type="text" name="enmName" id="empName" email: <input type="text" name="email" id="email" salary: <input type="text" name="salary" id="salary" Submit （10）添加删除记录-修改 添加删除记录练习 Name Email Salary Tom tom@tom.com 5000 Delete Jerry jerry@sohu.com 8000 Delete Bob bob@tom.com 10000 Delete 添加新员工 name: <input type="text" name="enmName" id="empName" email: <input type="text" name="email" id="email" salary: <input type="text" name="salary" id="salary" Submit （11）添加删除记录-a的索引问题 添加删除记录练习 Name Email Salary Tom tom@tom.com 5000 Delete Jerry jerry@sohu.com 8000 Delete Bob bob@tom.com 10000 Delete 添加新员工 name: <input type="text" name="enmName" id="empName" email: <input type="text" name="email" id="email" salary: <input type="text" name="salary" id="salary" Submit {nextPage/}（12）操作内联样式 点我一下 点我一下2 （13）获取元素的样式元素.currentStyle.样式名getComputdeStyle()方法 点我一下 getStyle方法 点我一下 （14）其他样式相关的属性HTML DOM Element 对象 练习 欢迎亲爱的用户注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 亲爱的用户，请仔细阅读以下协议，如果不仔细阅读就无法注册 我已仔细阅读 15、事件对象 {nextPage/}练习：跟随鼠标移动 (16)事件冒泡事件的冒泡：指事件的 向上 传导，当后代元素上的事件被触发时，其祖先元素的 相同事件 也会被触发在开发中，大部分的事件冒泡都是有用的。如果不希望发生事件冒泡可以通过事件对象来取消冒泡可以将事件对象的canceBubble=true用来取消冒泡 我是box1 我是span （17）冒泡的应用—事件的委派事件委派：将事件统一绑定给元素的祖先元素，这样当后代元素上的事件触发时，会一直冒泡到祖先元素，从而通过祖先元素的响应函数来处理事件事件委派是利用了冒泡，通过委派可以减少事件绑定的次数，提高程序的性能 添加超链接 我是P元素 超链接一 超链接二 超链接三 （18）事件的绑定 点我一下 （19）事件的传播事件的冒泡和捕获阶段{alert type="success"}微软公司认为事件是由内向外传播，也就是当事件触发时，应该先触发当前元素上的事件，然后再向元素当前元素的祖先元素上传播，也就是事件在冒泡阶段执行网景公司认为事件是由外向内传播，也就是当前事件触发时，应该先触发当前元素的最外层的祖先元素的事件，然后再向内传播给后代元素w3c综合了两个公司的方案，将事件传播分成了三个阶段捕获阶段：在捕获阶段时从外（最外层祖先元素）向内（目标元素）进行捕获，但是默认此时不会触发事件目标阶段：事件捕获到目标元素，捕获结束，开始在目标目标元素上触发事件冒泡阶段：事件从目标向他的祖先元素传递，依次触发祖先元素上的事件如果希望在捕获阶段就触发事件，可以将addEventListener()的第三个参数设置为true一般不会希望在捕获阶段触发事件，所以这个参数一般都是false{/alert}
内建对象二、函数的方法1、 call() 和 apply(){alert type="success"}这两个方法都是函数对象的方法，需要通过函数对象来调用当对函数调用call()和apply()都会调用函数执行在调用call()和apply()可以将一个对象指定为第一个参数，此时这个对象将会成为函数执行时的 thiscall()方法可以将实参在对象之后依次传递apply()方法需要将实参封装到一个数组中统一传递{/alert}this的情况：{alert type="error"}以函数形式调用时，this永远都是window以方法的形式调用时，this是调用方法的对象以构造函数的形式调用时，this是新创建的那个对象使用call()和apply()调用时，this是指定的那个对象{/alert}function fun(){ // alert(this.name); console.log("a="+a); console.log("b="+b); } var obj = { name:"obj", sayName:function(){ alert(this.name); } }; // fun.call(); // fun.apply(); // fun(); fun.call(obj,2,2); fun.apply(obj,[2,3]); var obj2 = { name:"obj2" }; fun.call(obj); fun.apply(obj2); // fun(); //this为window obj.sayName.apply(obj2); 三、 arguments 对象在调用函数时，浏览器每次都会传递进两个隐含的参数函数的上下文对象this封装实参的对象argumentsarguments是一个类数组对象，可以通过索引来操作数据，也可以获取长度在调用函数时，所传递的实参都会在arguments中保存arguments.length可以用来获取实参的长度即使不定义形参，也可以通过arguments来使用实参arguments[0]表示第一个实参arguments[1]表示第二个实参。。。。。。arguments里面有一个属性叫做callee，这个属性对应一个函数对象，就是当前正在指向的函数的对象function fun(){ // console.log(arguments instanceof Array); // console.log(Array.isArray(arguments)); // console.log(arguments.length); // console.log(arguments[1]); console.log(arguments.callee); } fun("hello",true);四、 Date对象在JS中使用Date对象来表示一个时间{alert type="success"}如果直接使用构造函数创建一个Date对象，则会封装为当前代码执行的时间创建一个指定的时间对象，需要在构造函数中传递一个表示时间的字符串作为参数日期的格式： 月份/日/年份 时:分:秒 {/alert}{alert type="error"}getDate() 获取当前日期对象是几日getDay() 获取当前日期对象是周几， 会返回0-6的值，0表示周日getMonth() 获取当前时间对象的月份， 会返回0-11的值，0表示1月.....11表示12月getFullYear() 获取当前时间对象的四位数年份getTime() 获取当前日期对象的时间戳时间戳，指的是从格林威治标准时间的1970年1月1日0时0分0秒到当前日期所花费的毫秒数 （1秒=1000毫秒）计算机底层在保存时间时使用的都是时间戳可以使用时间戳来测试代码执行的性能{/alert}//创建一个Date对象 var d = new Date(); //创建一个指定的时间对象 var d2 = new Date("12/03/2016 11:10:30") var date = d2.getDate(); var day = d2.getDay(); var month = d2.getMonth(); var year = d2.getFullYear(); var time = d2.getTime(); console.log("date="+date); console.log("day="+day); console.log("month="+month); console.log("year="+year); console.log("time="+time/1000/60/60/24/365); var d3 = new Date("1/1/1970 0:0:0");// 表示东八区北京时间 time = d3.getTime(): console.log(time); //获取当前的时间戳 time = Date.now(); console.log(time); var start = Date.now(); for(var i=0; i<100; i++){ console.log(i); } var end = Date.now(); console.log("执行了："+(end - start)+"毫秒");五、 Math对象Math和其他的对象不同，他不是一个构造函数，属于工具类不用创建对象，他里面封装了数学运算相关的属性和方法{callout color="#f0ad4e"}Math.PI 返回圆周率Math.abs() 返回数的绝对值Math.ceil() 可以对一个数进行向上取整，小数位只要有值就自动进1Math.floor() 可以对一个数进行向下取整，小数部分会被舍掉Math.round() 可以对一个数进行四舍五入取整Math.random() 可以用来生成0-1之间的随机数，生成一个x-y之间的随机整数： Math.round(Math.random()*(y-x)+x)Math.max() 可以获取多个数中的最大值Math.min() 可以获取多个数中的最小值Math.pow(x,y) 返回x的y次幂Matn.sqrt() 对一个数进行开方运算{/callout}console.log(Math.PI); //返回圆周率 console.log(Math.abs(-1)); //返回绝对值1 console.log(Math.ceil(1.1)); //向上取整，返回2 console.log(Math.floor(1.99)); //向下取整，返回1 console.log(Math.round(1.4)); //进行四舍五入取整，返回1 console.log(Math.random()); //生成一个0-1之间的随机数 //生成一个0-10的随机整数 for(var i=0; i<100; i++){ console.log(Math.round(Math.random()*10)); } var max = Math.max(10,45,30,100); var max = Math.min(10,45,30,100); console.log(max); console.log(min); console.log(Math.pow(12,3)); console.log(Math.sqrt(2)); console.log(max); console.log(min); console.log(Math.pow(12,3)); console.log(Math.sqrt(2)); //开方运算六、包装类基本数据类型： String Number Boolean Null Undefined引用数据类型：Object1、包装类在JS中提供了三个包装类，通过这三个包装类可以将基本数据类型的数据转换为对象在实际应用中不会使用基本数据类型的对象String() 可以将基本数据类型字符串转换为String对象Number() 可以将基本数据类型的数字转换为Number对象Boolean() 可以将基本数据类型的布尔值转换为Boolean对象var a = 123; var num = new Number(3); var num2 = new Number(3); var str = new String("hello"); var bool = new Boolean(true); var bool2 = true; //向num中添加一个属性 num.hello = "abcdef"; console.log(num.hello); console.log(num == num2);//返回false，对象永远不会相等 console.log(bool == bool2); // 返回true，会做转义比较 var b = new Boolean(fasle); if(b){ alert("能运行") } //方法和属性只能添加给对象，不能添加给基本数据类型 //当对一些基本数据类型使用包装类将其转换为对象，然后再调用对象的属性和方法 //调用完以后，再将其转换为基本数据类型，但是不会保存 var s = 123; s = s.toString(); s.hello = "你好"; console.log(s); console.log(s.hello);//返回undefined2、字符串的相关方法在底层字符串是以字符数组的形式保存的{callout color="#f0ad4e"}length属性 可以用来获取字符串的长度charAt() 可以返回字符串中指定位置的字符charCodeAt() 可以返回字符串中指定字符的字符编码（Unicode编码）formCharCode() 可以根据字符编码去获取字符concat() 可以用来连接两个或多个字符串indexOf() 可以从前向后检索一个字符串中是否含有指定内容,如果有则返回第一次出现的引索，如果不存在则返回-1，可以指定第二个参数指定开始查找的位置lastIndexOf() 该方法用法与indexOf()一样，不同的是该方法是从后往前找slice(开始截取索引,结束位置索引) 可以从字符串中截取指定的内容，不会影响原字符串，而是将截取到的内容返回substring(开始截取索引,结束位置索引) 可以截取一个字符串，和slice()类似，不同的是该方法不能接收负值，负值默认变为0，还会自动调整参数的位置，如果第二个参数小于第一个参数，则自动交换位置substr(开始位置的索引,截取的长度) 可以用来截取字符串split(字符串作为参数) 可以将一个字符串拆分为一个数组，如果传递一个空串作为参数，则会将每个字符都拆分为数组中的一个元素toUpperCase() 将一个字符串转换为大写并返回toLowerCase() 将一个字符串转换为小写并返回{/callout}//创建一个字符串 var str = "Hello nihao"; console.log(str.length); console.log(str[0]); // 返回H var result = str.charAt(1); console.log(result); //返回e var result1 = str.charCodeAt(1); console.log(result1); //返回101 //可以根据字符编码去获取字符 var result2 = String.formCharCode(0x2692); console.log(result2); //返回 锤子 var result3 = str.concat("你好","再见"); console.log(result3); //返回 hello你好再见 var result4 = str.indexOf("e",); console.log(result4); //返回1 str = "absadksbdjka"; result = str.slice(1,2); console.log(result); result = str.substring(2,1); console.log(result); str = "abc,bcd,def,fgh"; result = str.split(""); console.log(Array.isArray(result)); console.log(result); str = "abcdefg"; result = str.toUpprCace(); str = "ABCDEFG"; result = str.toLowerCace(); console.log(result);七、正则表达式1、正则表达式的简介用于定义一些字符串的规则，计算机可以根据正则表达式来检查一个字符串是否符合规则，或者将字符串中符合规则的内容提取出来语法： var 变量 = new RegExp("正则表达式","匹配模式";使用typeof检查正则对象，会返回object在构造函数中可以传递一个匹配模式作为第二个参数 i 忽略大小写g 全局匹配模式{alert type="success"}正则表达式的方法test() 可以用来检查一个字符串是否符合正则表达式的规则，符合返回true，否则返回false{/alert}//创建正则表达式的对象 var reg = new RegExp("a"); var str = "a"; var result = reg.test(str); console.log(result); console.log(reg.test("bcabc"));2、使用字面量创建正则表达式语法： var 变量 = /正则表达式/匹配模式; 使用字面量的方式创建正则表达式更加简单，但是使用构造函数创建更加灵活 var reg = new RegExp("a","i"); reg = /a/i; console.log(typeof reg); console.log(reg.test("abc")); //创建一个正则表达式，检查一个字符串中是否有a或b //使用|表示 或 的意思 reg = /a|b/; //创建一个正则表达式检查一个字符串在是否有字母 //[]里的内容也是 或 的关系 //[ab]=a|b //[a-z] 任意小写字母 //[A-Z] 任意大写字母 //[A-z] 任意字母 //[0-0] 任意数字 reg = /[A-z]/; //检查一个字符串中是否含有abc或adc或aec reg = /a[bde]c/; // [^ ] 除了方括号里的内容 reg = /[^ab]/; console.log(reg.test("bacd")); reg = /[0-9]/ console.log(reg.test(123));3、字符串和正则表达式相关的方法（1） split()将一个字符串拆分为一个数组该方法中可以传递一个正则表达式作为参数，则将会根据正则表达式去拆分字符串该方法即使不指定全局匹配，也会全部拆分var str = "1a2b3c4d5e6f7"; var result = str.split(/[A-z]/); console.log("result="+result);（2） search()可以搜索字符串中是否含有指定内容如果搜索到指定内容，则会返回第一次出现的索引，没有搜索到则返回-1可以接受一个正则表达式作为参数，然后根据正则表达式去检索字符串只会查找第一个，即使设置全局匹配也没用var str = "hello abc hello aec"; // 搜索字符串中是否含有abc或aec或afc var result = str.search(/a[bef]c/); console.log(result);（3） match()可以根据正则表达式从一个字符中将符合条件的内容提取出来{alert type="success"}默认情况下match只会找打第一个符合要求的内容，找到后就会停止检索可以设置正则表达式为全局匹配模式，这样会匹配到所以的内容可以为一个正则表达式设置多个匹配模式，且无顺序要求match()会将匹配到的内容封装到一个数组中返回，即使只查询到一个结果{/alert}var str = "1a2b3c4d5e6f7A8B9C"; var result = str.match(/[a-z]/ig); console.log("result="+result[2]);（4） replace()可以将字符串中指定内容替换为新的内容,默认只会替换第一个语法： replace(被替换的内容,新的内容)var str = "1a2b3c4d5e6f7A8B9C"; // 搜索字符串中是否含有abc或aec或afc var result = str.replace(/a-z/gi,""); console.log(result);4、正则表达式语法（1） 量词：可以设置一个内容出现的次数语法：var reg = /元素{次数}/{alert type="success"}量词只对它前边的一个内容起作用{n} 正好出现n次{m,n} 出现m至n次{n,} 出现n次以上+ 出现至少1次，相当于{1,}* 出现0个或多个，相当于{0,}? 出现0次或1次，相当于{0,1}^ 表示开头$ 表示结尾如果在正则表达式中同时使用 ^ 和 $ 则要求字符串必须完全符合正则表达式{/alert}//创建一个正则表达式，检查一个字符串中是否含有aaa var reg = /a{3}/; reg = /(ab){3}/; reg = /b{3}/; reg = /ab{3}c/; reg = /ab{1,3}c/; reg = /ab{3,}c/; reg = /ab+c/; reg = /ab*c/; reg = /ab?c/; console.log(reg.test("abbbbbc")); //检查一个字符串是否以a开头 reg = /^a/; //匹配开头的a reg = /a$/; //匹配结尾的a console.log(reg.test("abbbbbca")); reg = /^a$/; console.log(reg.test("a"));例：创建一个正则表达式，用来检查一个字符串是否为一个合法的手机号/*手机号的规则 1 3 567890123（11位） 1、以1开头 2、第二位3-9任意数字 3、三位以后任意数字9个 ^1 [3-9] [0-9]{9}$ */ var phoneStr = "13567890123"; var phoneReg = /^1[3-9][0-9]{0}$/; console.log(phoneReg.test(phoneStr));（2）元字符{callout color="#b8cf89"}. 表示任意字符在正则表达式中使用作为转义字符\. 表示.\\ 表示\注意：使用构造函数时，由于他的参数是一个字符串，而 \ 是字符串中转义字符，如果要使用 \ 则需要使用 \\ 来代替{/callout}{alert type="success"}\w 任意字母、数字、_ ，相当于 [A-z0-9_]\W 除了字母、数字、_ ，相当于 [^A-z0-9_]\d 任意数字，相当于[0-9]\D 除了数字，相当于[/^0-9]\s 空格\S 除了空格\b 单词边界,用来标记一个独立的单词\B 除了单词边界{/alert}//检查一个字符串中是否含有. var reg = /\./; console.log(reg.test("@#ad.c")); var reg = /\\/; console.log(reg.test("b.\\")); console.log("b.\\");//输出 b.\ reg = new RegExp("\\."); console.log(reg); reg = /\w/; reg = /\W/; console.log(reg.test("_")); reg = /\s/; reg = /\S/; //创建一个正则表达式检查一个字符串中是否含有单词child reg = /\bchild\b/; console.log(reg.test("hello child")); //接收一个用户的输入 //var str prompt("请输入你的用户名:"); var str = " he llo "; //去除字符串中的空格 //去除空格就是使用""空串来替换空格 console.log(str); //str = str.replace(/\s/g,""); //去除开头的空格^ str = str.replace(/^\s*/,""); //去除结尾的空格$ str = str.replace(/\s*$/,""); //整合为一个表达式，使用|和g来进行全局匹配 str = str.replace(/^\s*|\s*$/g,""); console.log(str);5、邮件的正则表达式/* hello.nihao@abc.com.cn 任意字母数组下划线.任意字母下划线@任意字母数组.任意字母（2-5位）.任意字母（2-5位） */ // \w{3,} (\.\w+)* @ [A-z0-9]+ (\.[A-z]{2,5})(1,2) var emailReg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5})(1,2)$/; var email = "abc@abc.com.123"; console.log(emailReg.test(email));
this解析器（浏览器）在调用函数时每次都会向函数内部传递进一个隐含的参数1、this的定义{alert type="success"}这个隐含的参数就是this，this指向的是一个对象，这个对象我们称为函数执行的上下文对象根据函数的调用方式的不同，this会指向不同的对象1、 以函数的形式调用时，this永远都是window2、 以方法的形式调用时，this就是调用方法的那个对象 {/alert}function fun(){ //console.log("a=" +a+",b="+b); console.log(this.name); } fun();//输出object.window //创建一个对象 var obj = { name:"孙悟空", sayName:fun }; var obj2 = { name:"沙和尚", sayName:fun }; //console.log(obj.sayName == fun);//输出true var name = "全局的name属性" obj.sayName();//输出object.object [name:"孙悟空",sayName:fun] //以函数形式调用,this时window fun(); //以方法的形式调用，this是调用方法的对象 obj.sayName(); obj2.sayName();2、this补充//创建一个name变量 var name = "全局"; //创建一个fun()函数 function fun(){ console.log(this.name); } //创建两个对象 var obj = { name:"孙悟空", sayName:fun }; var obj2 = { name:"沙和尚", sayName:fun }; //调用obj.sayName()时输出obj的名字 obj.sayName();//输出 孙悟空 obj2.sayName();//输出 沙和尚对象1、使用工厂方法创建对象可以使用该方法大批量创建对象使用工厂方法创建的对象使用的构造函数都是Object所以创建的对象都是Object类型，导致无法区分出多种不同类型的对象function createPerson(name,age,gender){ //创建一个新的对象 var obj = new Object(); //向对象中添加属性 obj.name = name; obj.age = age; obj.gender = gender; obj.sayName = function(){ alert(this.name); } //将新的对象返回 return obj; } var obj2 = createPerson("猪八戒",18,"男"); var obj3 = createPerson("白骨精",17,"女"); var obj4 = createPerson("蜘蛛精",16,"女"); console.log(obj2); console.log(obj3); console.log(obj4); obj2.sayName();2、构造函数{alert type="success"}构造函数就是一个普通函数，创建方式和普通函数没有区别，不同的是构造函数习惯上首字母大写构造函数和普通函数的区别就是调用的方式不同，普通函数是直接调用， 而构造函数需要使用 new 关键字俩调用使用同一个构造函数创建的对象称为一类对象，也将一个构造函数称为一个类将通过一个构造函数创建的对象称为该类的实例 {/alert}构造函数的执行流程： {alert type="warning"}立刻创建一个新的对象将新建的对象设置为函数中的this逐行执行函数中的代码将新建的对象作为返回值返回{/alert}使用同一个构造函数创建的对象，称为一类对象，也将构造函数称为一个类{alert type="success"}通过一个构造函数创建的对象，称为该类的实例{/alert}使用instanceof可以检查一个对象是否是一个类的实例 语法： 对象 instanceof 构造函数 {alert type="success"}如果是返回true，否则返回false所有的对象都是Object的后代任何对象和Object作instanceof检查时都会返回true {/alert}//创建一个构造函数，专门用来创建Person对象 var per = new Person(); function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; this.sayNmae = function(){ alert(this.name); }; } var per = new Person("孙悟空",18，"男") var per = new Person("玉兔精",17，"女") console.log(per); console.log(per instanceof Person);this的情况： {alert type="error"}1、当以函数的形式调用时，this是window2、当以方法的形式调用时，谁调用方法this就是谁3、当以构造函数的形式调用时，this就是新创建的那个对象{/alert}3、构造函数修改在Person构造函数中，为每一个对象都添加了一个sayName方法//创建一个Person构造函数 function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; //向对象中添加一个方法 this.sayName = function(){ alert("Hello大家好，我是："+this.name); }; } //创建一个Person的实例 var per = new Person("孙悟空",18,"男"); var per = new Person("猪八戒",19,"男"); per.sayName();方法是在构造函数内部创建的，构造函数每执行一次就会创建一个新的sayName方法， 也就是所有实例的sayName都是唯一的会导致构造函数每执行一次就会创建一个新的方法可以将将sayName方法在全局作用域中定义（尽量不要将函数定义在全局作用域）{alert type="info"}将函数定义在全局作用域会污染全局作用域的命名空间而且定义在全局作用域中也很不安全{/alert}//创建一个Person构造函数 function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; //向对象中添加一个方法 this.sayName = fun; }; } //将sayName方法在全局作用域中定义 function fun(){ alert("Hello大家好，我是："+this.name); //创建一个Person的实例 var per = new Person("孙悟空",18,"男"); var per = new Person("猪八戒",19,"男"); per.sayName();4、原型对象原型 prototype 创建的每一个函数，解析器都会向函数中添加一个属性prototype{alert type="success"}这个属性对应着一个对象，这个对象就是原型对象如果函数作为普通函数调用prototype没有任何作用当函数以构造函数的形式调用时，它所创建的对象中都会有一个隐含的属性，指向该构造函数的原型对象，可以通过 __proto__ 来访问该属性原型对象就相当于一个公共的区域，所以同一个类的实例都可以访问到这个原型对象可以将对象中共有的内容，统一设置到原型对象中当访问对象的一个属性时，它会先在对象自身找，如果有则直接使用，如果没有则会向原型对象中选择，如果找到会直接使用{/alert}function MyClass(){ } //向MyClass的原型中添加属性a MyClass.prototype.a = 123; //向MyClass的原型中添加一个方法 MyClass.prototype.sayHello = function(){ alert("hello"); }; var mc = new MyClass(); console.log(MyClass.prototype); console.log(mc.__proto__ == MyClass.prototype);//输出true console.log(mc.a);//输出123 //向mc中添加a属性 mc.a = "我是mc中的a"; console.log(mc.a);//输出 我是mc中的a mc.sayHello();//输出 弹窗hello创建构造函数时，可以将这些对象共有的属性和方法，统一添加到构造函数的原型对象中这样不用分别为每一个对象添加，就可以使每个对象都具有这些属性和方法，也不会影响到全局作用域例：//创建一个Person构造函数 function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; //向中添加一个方法 // this.sayName = fun; }; } //向原型中添加sayName方法 Person.prototype.sayName = function(){ alert("Hello大家好，我是："+this.name); //创建一个Person的实例 var per = new Person("孙悟空",18,"男"); var per = new Person("猪八戒",19,"男"); per.sayName(); // 输出弹窗补充： {alert type="success"}使用 in 检查对象中是否含有某个属性时，如果对象中没有单数原型中有，也会返回true可以使用对象的 hasOwnProperty() 来检查对象自身是否含有该属性使用该方法只有当对象自身含有该属性时才会返回true原型对象也是对象，所以他也有原型 当使用一个原型一个对象的属性或方法时，会先在自身中寻找，自身中如果有则直接使用，如果没有则去原型对象中寻找，如果原型对象中有则使用，如果没有则去原型的原型中寻找，直到找到Object对象的原型 Object对象的原型没有原型，如果在Object的原型中依然没有找到则返回undefined {/alert}//创建一个构造函数 function MyClass(){ } //向MyClass的原型中添加一个name属性 MyClass.prototype.name = "我是原型中的name"; var mc = new MyClass(); console.log(mc.name); //使用in检查对象中是否含有某个属性时，如果对象中没有单数原型中有，也会返回true console.log("name" in mc); //输出 true //可以使用对象的hasOwnProperty()来检查对象自身是否含有该属性 //使用该方法只有当对象自身含有该属性时才会返回true console.log(mc.hasOwnProperty("name"));//返回false console.log(mc.hasOwnProperty("hasOwnProperty"));//返回false console.log(mc.__protp__.hasOwnProperty("hasOwnProperty"));//输出false console.log(mc.__proto__.__proto__.hasOwnProperty("hasOwnProperty"));//输出true5、toString{alert type="success"}当直接在页面中打印一个对象时，实际上是输出的对象的 toString() 方法的返回值如果希望在输出对象时不输出 [object Object] ，可以为对象添加一个 toString() 方法{/alert}function Person(name,age,gender){ this.name = name; this.age = age; this.gender = gender; } //修改Person原型中的toString Person.prototype.toString = function(){ return "Person[name="+this.name+",age="+this.age+",gender="+this.gender+"]" }; //创建一个Person实例 var per = new Person("孙悟空",18,"男"); var per2 = new Person("猪八戒",28,"男"); //console.log(per); //console.log(per.toString);//与上面相同 /*输出Person[name=孙悟空,age=18,gender=男] per.toString = function(){ return "Person[name="+this.name",age="+this.age",gender="+this.gender"]" }; */ var result = per.toString(); //console.log("result = "+result); //console.log(per.__pro__.__pro__.hasOwnProperty("toString"));//返回true console.log(per); console.log(per2);6、垃圾回收（GC）当一个对象没有任何的变量或者属性对它进行引用时，将永远无法操作该对象，此时这种对象就是一个垃圾这种对象过多会占用大量的内存空间，导致程序运行过慢，所以这种垃圾必须进行清理{alert type="success"}程序运行过程中会产生垃圾，垃圾积攒过多以后，会导致程序运行的速度过慢所以需要一个垃圾回收的机制，来处理程序运行过程中产生的垃圾在JS中拥有自动的垃圾回收机制，会自动将这些垃圾对象从内存中销毁不需要也不能进行垃圾回收的操作， 要做的只是将不再使用的对象设置null即可 {/alert}//创建一个对象 var obj = new Object(); //对对象进行各种操作。。。。 obj = null;{nextPage/}内建对象对象的类型：内建对象、宿主对象、自定义对象一、数组1、数组（Array）的简介{alert type="success"}数组也是一个对象，和普通对象功能类似，也是用来存储一些值的不同的是普通对象是使用字符串作为属性名的，而数组是使用数字来作为索引操作元素的索引（index）：从0开始的整数就是索引数组的存储性能比普通对象要好 ，所以在开发中经常使用数组来存储一些数据{/alert}向数组中添加元素，语法： 数组[索引] = 值读取数组中的元素，语法： 数组[索引]{alert type="error"}如果读取不存在的索引，不会报错而是返回undefined可以使用 length 属性来获取数组的长度（元素的个数），语法： 数组.length对于连续的数组，使用 length 属性可以获取数组的长度（元素的个数）对于非连续的数组，使用 length 属性会获取数组的最大索引+1尽量不要创建非连续的数组,会空出不存在的元素的位置，占用内存向数组的最后一个位置添加元素，语法： 数组[数组.length] = 元素; {/alert}//创建数组对象 var arr = new Array(); //使用typeof检查一个数组时，会返回Object console.log(typeof arr); //向数组中添加元素 arr[0] = 10; arr[1] = 33; arr[2] = 22; arr[3] = 25; //arr[10] = 21; //arr[100] = 210; //console.log(arr[3]);//输出undefined //获取数组的长度 console.log(arr.length); console.log(arr); //修改length /* 如果修改的length大于原长度，则会空出多出的元素 如果修改的length小于原长度，则会删除多出的元素 */ //arr[10] = 21; arr[2] = 22; //向数组的最后一个位置添加元素 arr[arr.length] = 20; console.log(arr.length); console.log(arr);2、数组字面量使用字面量来创建数组，语法：[]{alert type="success"}使用字面量创建数组时，可以在创建时就指定数组中的元素使用构造函数创建数组时，也可以同时添加元素，将要添加的元素作为构造函数的参数传递元素之间使用 , 隔开数组中的元素可以是任意的数据类型，也可以是对象，亦可以是一个函数{/alert}//var arr = new Array(); /* 无意义 arr[0] = 123; arr.hello = "abc"; console.log(arr.hello); */ //使用字面量来创建数组 //var arr = []; var arr = [1,2,3,4,5,6,10]; console.log(arr[1]); console.log(arr.length); var arr = new Array(10,20,30); console.log(arr2); //创建一个数组中只有一个元素10 arr = [10]; //创建一个长度为10的数组 arr2 = new Array(10); console.log(arr[0]); console.log(arr2); //数组中的元素可以是任意的数据类型 arr = [10,"hello",true,null,undefined]; var obj = {name:"孙悟空"}; arr[arr.length] = obj; arr = [{name:"孙悟空"},{name:"沙和尚"},{name:"猪八戒"}] console.log(arr[1].name); arr = [function(){alert(1)},function({alert(2)})]; //console.log(arr); arr[0](); //数组中可以放数组，如下这种数组称为二维数组 arr = [[1,2,3],[3,4,5],[5,6,7]]; console.log(arr[1]);3、数组的方法（1） push() ：语法： 数组.push(参数一,参数二,参数N); 可以向数组的末尾添加一个或多个元素，并返回数组新的长度{/alert}{alert type="success"}可以将要添加的元素作为方法的参数传递，这些元素将会自动添加到数组的末尾该方法会将数组新的长度作为返回值返回{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var result = arr.push("唐僧","蜘蛛精","白骨精"); console.log(arr); console.log("result = "+result); （2） pop() :语法： 数组.pop(); 该方法可以删除啊数组的最后一个元素，并将被删除的元素作为返回值返回，删除几次就写几次//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var result = arr.push("唐僧","蜘蛛精","白骨精","玉兔精"); arr.pop(); arr.pop(); console.log(arr); console.log("result = "+result); （3） unshift()语法： 数组.unshift(参数一,参数二，参数N); {alert type="success"}向数组开头添加一个或多个元素，并返回新的数组长度向前边插入元素以后，其他的元素索引会依次调整{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var result = arr.push("唐僧","蜘蛛精","白骨精","玉兔精"); arr.unshift("牛魔王","二郎神"); console.log(arr); console.log("result = "+result);（4） shift()语法： 数组.shift(); 可以删除数组的第一个元素，并将被删除的元素作为返回值返回,要删除几个就写几个//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var result = arr.push("唐僧","蜘蛛精","白骨精","玉兔精"); arr.shift(); console.log(arr); result = arr.shift(); console.log("result = "+result);（5） slice()语法： 数组.slice(参数一,参数二); 可以从已有的数组中返回选定的元素参数：截取开始的位置的索引，包含开始索引截取结束的位置的索引，不包含结束索引{alert type="success"}该方法不会改变原数组，而是将截取到的元素封装到一个新的数组中返回第二个参数可以省略不写，此时会截取从开始索引以后的所有元素索引也可以传递一个负值，如果传递负值则从后往前计算，例：-1：倒数第一个{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚","唐僧","玉兔精"]; var result = arr.slice(0,2); console.log(result);（6） splice()语法： 数组.splice(参数一,参数二,参数三,参数N); 可以用于删除数组中的指定元素，并向数组中添加新的元素参数：第一个：开始的位置的索引第二个：删除的数量第三个及以后的参数可以传递一些新的元素，这些元素将会自动插入到开始位置的索引前面{alert type="success"}使用该方法会改变原数组，会将指定元素从原数组中删除，并将被删除的元素作为返回值返回{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚","唐僧","玉兔精"]; var result = arr.splice(1,0,"牛魔王","红孩儿"); console.log(result);（7）数组去重练习//创建一个数组 var arr = [1,2,3,2,1,3,4,2,5]; //去除数组中重复的数字解法：//创建一个数组 var arr = [1,2,3,2,2,1,3,4,2,5]; //去除数组中重复的数字 //获取数组中的每一个函数 for(var i=0; i<arr.lenth; i++){ //console.log(arr[i]); for(var j=i+1; j<arr.lenth; j++){ //console.log(arr[j]); //判断两个元素的值是否相等 if(arr[i] == arr[j]){ //如果相等则证明出现了重复的元素，删除j对应的元素 arr.splice(j,1); //当删除了当前j所在的元素以后，后面的元素会自动补位 //此时将不会再比较这个元素，需要再比较一次j所在位置的元素 //当删除一个元素后，使j自减 j--; } } } console.log(arr);（8） concat()语法： 数组.concat(); 连接两个或多个数组，并将新的数组返回{alert type="success"}该方法不会改变原数组，可以添加数组，也可以添加元素{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var arr2 = ["白骨精","玉兔精","蜘蛛精"]; var arr2 = ["二郎神","太乙真人","太上老君"]; var result = arr.concat(arr2,arr3,"牛魔王"); console.log(result);（9） join()语法： 数组.join("连接符"); 该方法可以将数组转换为一个字符串{alert type="success"}该方法不会改变原数组，而是将转换后的字符串作为结果返回在join()中可以指定一个字符串作为参数，这个字符串将会成为数组中元素的连接符如果不指定连接符，则默认使用 , 连接{/alert}//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; var result = arr.join("-"); console.log(typeof result);//输出string console.log(result);//输出 孙悟空-猪八戒-沙和尚（10） reverse()语法： 数组.reverse(); 该方法用来反转数组（前边的去后边，后边的去前边）该方法会直接修改原数组//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚"]; arr.reverse(); console.log(arr);//输出 沙和尚,猪八戒,孙悟空（11） sort()语法： 数组.sort(); 该方法可以用来对数组中的元素进行排序该方法会影响原数组，默认会按照Unicode编码进行排序{alert type="error"}使用sort()排序时，即使对于纯数字进行排序，也会按照Unicode编码来排序，可能会得到错误的结果可以指定排序的规则可以在sort()添加一个回调函数，来制定排序规则，回调函数中需要定义两个形参，浏览器将会分别使用数组中的元素作为实参去调用回调函数浏览器会根据回调函数的返回值来决定元素的顺序 1. 如果返回一个大于0的值，则元素交换位置2. 如果返回一个小于0的值，则元素位置不变 3. 如果返回一个等于0的值，则认为两个元素相等，也不交换位置 {/alert}//创建一个数组 var arr = [5,4,2,1,3,6,8,7]; arr.sort(); console.log(arr);//输出 a,b,d //arr.reverse(); console.log(arr);//输出 d,b,a arr.sort(function(a,b){ // if(a>b){ // return 1; // }else if(a<b){ // return -1; // }else{ // return 0; // } //升序排列 return a - b; //降序排列 return b - a; }); console.log(arr);4、数组的遍历遍历数组：就是将数组中的所有元素都取出来//创建一个数组 var arr = ["孙悟空","猪八戒","沙和尚","唐僧","玉兔精"]; /*console.log(arr[0]); console.log(arr[1]); console.log(arr[2]); */ for(var i=0; i<arr.length; i++){ console.log(arr[i]); }5、数组练习创建一个函数，可以将perArr中的满18岁的Person提取出来，然后封装到一个新的数组中并返回，arr 形参：要提取信息的数组function Person(name,age,gender){ this.name = name; this.age = age; } //修改Person原型中的toString Person.prototype.toString = function(){ return "Person[name="+this.name+",age="+this.age+"]" }; //创建一个Person对象 var per = new Person("孙悟空",18); var per2 = new Person("猪八戒",28); var per3 = new Person("红孩儿",8); var per4 = new Person("蜘蛛精",16); var per5 = new Person("二郎神",38); //将这些person对象放入到一个数组中 var perArr = [per,per2,per3,per4,per5]; /*创建一个函数，可以将perArr中的满18岁的Person提取出来，然后封装到一个新的数组中并返回 arr 形参，要提取信息的数组 */ function getAdult(arr){ //创建一个新的数组 var newArr = []; //遍历arr，获取arr中的Person对象 //判断Person对象的age是否大于等于18 //如果大于等于18，则将这个对象添加到newArr中 //将新的数组返回 return newArr; } var result = getAdult(perArr); console.log(result);解法：//遍历arr，获取arr中的Person对象 for(var i=0; i<arr.length; i++){ var p = arr[i]; //判断Person对象的age是否大于等于18 if(p.age>=18){ //如果大于等于18，则将这个对象添加到newArr中 newArr.push(p); } }6、 forEach()一般都是使用for循环遍历数组，JS中还提供了一个 forEach() 方法来遍历数组，但是只支持IE8以上浏览器，所以需要兼容IE8尽量不要使用该方法{alert type="success"}forEach()方法需要一个函数作为参数这种函数有我们创建单数不由我们调用的，称为回调函数数组中有几个元素，函数就会执行几次，每次执行时浏览器会将遍历到的元素以实参的形式传递进来，可以定义形参来读取这些内容浏览器会在回调函数中传递三个参数第一个参数：当前正在遍历的元素，第二个参数：当前正在遍历的元素的索引，第三个参数：当前正在遍历的数组 {/alert}var arr = ["孙悟空","猪八戒","沙和尚","唐僧","玉兔精"]; arr.forEach(function(value,index,obj){ console.log("value ="+value); console.log("index ="+index); console.log("obj ="+obj); });
对象JS中的数据类型{alert type="success"}String 字符串Number 数值Boolean 布尔值Null 空值Undefined 未定义以上五种类型属于基本类型，只要不是以上五种，都是对象Object 对象{/alert}基本数据类型都是单一的值，值和值之间没有任何联系在JS中用来表示一个人的信息（name gender age）var name="张三"; var gender="男"; var age="18";如果使用基本数据类型，创建的变量都是独立的，不能成为一个整体对象属于一种复合的数据，在对象中可以保存多个不同数据类型的属性一、对象的分类1、内建对象{alert type="success"}由ES标准中定义的对象，在任何的ES的实现中都可以使用比如：Math String Number Boolean Function Object……{/alert}2、宿主对象{alert type="success"}由JS的运行环境提供的对象，主要由浏览器提供的对象比如：BOM(浏览器对象模型) DOM(文档对象模型){/alert}console.log(); document.write(); //都是由浏览器提供3、自定义对象{alert type="success"}由开发人员自己创建的对象{/alert}二、创建对象1、 使用 new 关键字调用的函数，是构造函数constructor2、 构造函数是专门用来创建对象的函数3、 使用typeof来检查一个对象时，会返回object{alert type="warning"}在对象中保存的值称为属性向对象添加属性，语法： 对象.属性名=属性值; {/alert}var obj = new Object(); //console.log(typeof obj); //向obj添加一个name属性 obj.name="张三"; //向obj添加一个gender属性 obj.gender="男"; //向obj添加一个age属性 obj.age="18"; console.log(obj);{alert type="warning"}读取对象中的属性语法： 对象.属性名; 如果读取对象中没有的值，不会报错而是会返回undefined{/alert}var obj = new Object(); //向obj添加一个name属性 obj.name="张三"; //向obj添加一个gender属性 obj.gender="男"; //向obj添加一个age属性 obj.age="18"; console.log(obj.name);//输出“张三”{alert type="warning"}修改对象中的属性语法： 对象.属性名 = 新值; {/alert}var obj = new Object(); //向obj添加一个name属性 obj.name="张三"; //向obj添加一个gender属性 obj.gender="男"; //向obj添加一个age属性 obj.age="18"; //修改obj的name属性值 obj.name="孙悟空" console.log(obj.name);//输出“孙悟空”{alert type="warning"}删除对象中的属性语法： delete 对象.属性名; {/alert}var obj = new Object(); //向obj添加一个name属性 obj.name="张三"; //向obj添加一个gender属性 obj.gender="男"; //向obj添加一个age属性 obj.age="18"; //删除obj的name属性值 delete obj.name; console.log(obj.name);//没有该值，输出undefined三、属性名和属性值1、属性名对象的属性名不强制要求遵守标识符的规范尽量按照标识符的规范设置{alert type="success"}如果使用特殊的属性名，不能采用.的方式来操作需要使用另一种方式，语法： 对象["属性名"]=属性值;读取时也需要采用这种方式使用[]这种形式去操作属性更加灵活在[]中可以直接传递一个变量，这样变量值是多少就会读取那个属性{/alert}var obj = new Object(); obj["123"]=567; obj["nihao"]="你好"; var n = "nihao" console.log(obj["123"]); console.log(obj[n]); 2、属性值JS对象的属性值，可以是任意的数据类型， 甚至也可以是一个对象 {alert type="warning"}in 运算符通过该运算符可以检查一个对象中是否含有制定的属性，有返回true，没有则返回false语法："属性名" in 对象{/alert}var obj = new Object(); obj.name="孙悟空"; obj.test= true; obj.test= null; obj.test= undefined; var obj2 = new Object(); obj2.name="猪八戒"; obj.test=obj2; console.log(obj.test);//返回 name=“猪八戒” console.log(obj.test.name);//返回 “猪八戒” console.log("name" in obj);//返回true四、基本、引用数据类型（一）基本数据类型String Number Boolean null Undefined{alert type="success"}JS中的变量都是保存在栈内存的基本数据类型的值直接在栈内存中存储值与值之间是独立存在的，修改一个变量不会影响其他变量{/alert}var a = 123; var b = a; a++; console.log("a"= +a); //输出为124 console.log("b"= +b); //输出为123（二）引用数据类型对象：Object{alert type="success"}JS中的变量都是保存在栈内存的对象是保存到堆内存中的，每创建一个新的对象，就会在堆内存中开辟一个新的空间而变量保存的是对象的内存地址（对象的引用），如果两个变量保存的是同一个对象引用当通过一个变量修改属性时，另一个也会受到影响{/alert}var obj = new Object(); obj.name = "孙悟空"; var obj2 = obj; console.log(obj.name);//输出 孙悟空 console.log(obj2.name);//输出 孙悟空 //修改obj的name属性 obj.name = "猪八戒"; console.log(obj.name);//输出 猪八戒 console.log(obj2.name);//输出 猪八戒 obj2 = null; console.log(obj);//输出 Object console.log(obj2);//输出 null{alert type="success"}当比较两个基本数据类型的值时，就是比较他们的值当比较两个引用数据类型时，是比较对象的内存地址 如果两个对象一模一样，但是地址不同，它也会返回false{/alert}var a = 10; var b = 10; console.log(a == b); // 返回true var obj3 = new Object(); var obj4 = new Object(); obj3.name = "沙和尚"; obj4.name = "沙和尚"; console.log(obj3 == obj4); // 返回false五、对象字面量使用对象字面量，可以在创建对象时，直接指定对象的属性语法： {属性名:属性值,属性名:属性值....} {alert type="success"}对象字面量的属性名可以加引号也可以不加， 建议不加如果要使用一些特殊的名字，则必须加引号属性名和属性值是一组一组的名值对结构名和值之间使用冒号 : 连接多对名值之间使用逗号 , 隔开如果一个属性之后没有其他属性时， 就不要写逗号 , 了 {/alert}//创建一个对象 //var obj = new Object(); //使用对象字面量来创建一个对象 var obj = {}; obj.name = "孙悟空"; var obj2 = { name:"猪八戒", age:28, gender:"男" test:{ name:"沙和尚", age:27 } }; console.log(obj2.test);//输出name:沙和尚 age:27函数一、函数的简介函数（function）：也是一个对象{alert type="warning"}普通对象只能封装属性函数对象可以封装一些功能（代码），在需要时可以执行这些功能函数可以保存一些代码在需要时调用使用typeof检查一个函数时会返回function{/alert}1、使用构造函数的方式来创建函数{alert type="success"}可以将要封装的代码以字符串的形式传递给构造函数封装到函数中的代码不会立即执行函数中的代码会在函数调用的时候执行调用函数，语法： 函数对象() 当调用函数时，函数中封装的代码会按照顺序执行在实际开发中很少使用构造函数来创建一个函数 {/alert}var fun = new Function( "console.log('这是我的第一个函数');" ); fun.hello = "你好"; console.log(fun.hello);//输出 你好 fun();//输出 这是我的第一个函数2、使用函数声明来创建一个函数语法：中括号可选，可不写function 函数名([形参1，形参2，形参n]){ 语句... }function fun2(){ console.log("这是我的第二个函数"); alert("哈哈哈哈"); document.write("你好"); } fun2();//按顺序输出3个函数3、使用函数表达式来创建一个函数语法：var 函数名 = function([形参1,形参2,形参n]){ 语句... }将一个匿名函数赋值给一个变量var fun3 = function (){ console.log("这是一个匿名函数"); } fun3();二、函数的参数1、形参与实参可以在函数的()中来指定一个或多个形参（形式参数）{alert type="success"}多个形参之间使用 , 隔开，声明形参就相当于在函数内部声明了对应的变量，但是 并不赋值在函数调用时，可以在()中指定实参（实际参数）实参将会赋值给函数中对应的形参调用函数时解析器不会检查实参的类型（可能会存在非法参数）调用函数时解析器也不会检查实参的数量（多余实参不会被赋值）函数的实参可以是任意的数据类型如果实参的数量少于形参的数量，则没有对应实参的形参将会是undefined{/alert}function sum(){ var a = 1; var b = 1; console.log(a+b); } sum(); // 输出 求和值2 //a,b都是形参 function sum (a,b){ cosole.log(a+b+c); } //1,2都是实参，实参可以是任意数据类型 sum(1,2);//输出 求和值3 //3没有对应的形参，将变为undefined sum(1,2,3);//输出 求和值null2、函数的返回值可以使用return来设置函数的返回值语法： return 值{alert type="success"}return后的值将会作为函数的执行结果返回可以定义一个变量来接受该结果在return后的语句不会再执行如果return语句后不跟任何值就相当于返回一个undefined函数中不写return也会返回undefined{/alert}function sum(a,b,c){ // alert(a+b+c); var d = a+b+c; return d; //return; alert("hello"); } //调用函数 // sum(1,2,3) //变量result的值就是函数的执行结果 //函数返回什么result的值就是什么 var result = sum(4,7,8); console.log("result="+result);//输出 求和值193、实参的类型例1： 定义一个函数，判断一个数字是否为偶数，如果是返回true，否则返回falsefunction isOu(num){ if(unm % 2 == 0){ return true; }else{ return false; } //相等于上面的式子 return num % 2 == 0 ; } var result = isOu(2); console.log("result = "+result);//输出true例2： 定义一个函数，可以根据半径计算一个圆的面积，并返回计算结果function mianji(r){ return 3.14*r*r; } var result = mianji(10); console.log("result = "+result);//输出314例3： 创建一个函数，可以在控制台输出一个人的信息实参可以是任意的数据类型，也可以是一个对象当参数过多时，可以将参数封装到一个对象中，然后通过对象传递function sayHello(o){ console.log("我是"+o.name+",今年我"+o.age+"岁了，"+"我是一个"+o.gender+"人，我住在"+o.address); } //创建一个对象 var obj = { name:"孙悟空", age:18, address:"花果山", gender:"男" }; sayHello(obj);例4： 实参可以是一个对象，也可以是一个函数{alert type="warning"}fun(sayHello) 函数对象，相当于直接调用函数对象fun(sayHello()) 调用函数，相当于使用函数的返回值{/alert}function sayHello(o){ console.log("我是"+o.name+",今年我"+o.age+"岁了，"+"我是一个"+o.gender+"人，我住在"+o.address); } //创建一个对象 var obj = { name:"孙悟空", age:18, address:"花果山", gender:"男" }; function fun(a){ console.log("a = "+a);//输出sayHello整个函数 a(obj);//输出sayHello(obj);的结果 } fun(sayHello); fun(sayHello());//输出函数sayHello的返回值4、返回值的类型function fun(){ alert("函数要执行了")； for(var i=0; i<5; i++){ console.log(i); if(i == 2){ break;//break可以退出当前循环 continue;//用于跳过当次循环 return;//可以结束整个函数 } console.log(i); } alert("函数执行完了"); } fun();{alert type="warning"}返回值可以是任意数据可以是对象，也可以是一个函数{/alert}function fun2(){ //var obj = {name:"沙和尚"}; //return obj; return {name:"沙和尚"}; } var a = fun2(); console.log("a="+a.name); function fun3(){ //在函数内部再声明一个函数 function fun4(){ alert("我是fun4"); } //fun4(); return fun4;//fun4函数作为返回值返回 return fun4(); } //a = fun3(); //console.log(a); //a(); fun3()();5、立即执行函数{alert type="warning"}h函数定义完成立即被调用，这种函数叫做立即执行函数立即执行函数一般只会执行一次{/alert}(function(){ alert("我是一个匿名函数"); })(); (function(a,b){ console.log("a = "+a); console.log("b = "+b); })(123,456);6、对象的方法对象的属性值可以是任意数据内心，也可以是一个函数{alert type="warning"}如果一个函数作为一个对象的属性保存，那么这个函数就是这个对象的方法调用这个函数就是调用对象的方法（method）但是它只是名称上的区别，没有其他区别{/alert}var obj = new Object(); obj.name = "孙悟空"; obj.age = 18; obj.sayName function(){ console.log(obj.name); }; function fun(){ console.log(obj.name); } //console.log(obj.sayName); //调用obj的sayName方法 obj.sayName(); //调用函数 fun(); var obj2 = { name:"猪八戒", age:18, sayNme:function(){ console.log(obj2.name); } }; obj2.sayName();7、枚举对象中的属性使用 for...in 语句来枚举对象中的属性语法：for(var 变量 in 对象){ }{alert type="success"}for...in 语句，对象中有几个属性，循环体就会执行几次每次执行时会将对象中的一个属性的名字赋值给变量{/alert}var obj = { name:"孙悟空", age:18, gender:"男", address:"花果山" }; //[]可以传变量 for(var n in obj){ console.log("属性名:"+n); console.log("属性值:"+obj[n]); }三、作用域{alert type="success"}作用域指一个变量的作用的范围在JS中共有两种作用域1、全局作用域2、函数作用域（区域作用域） {/alert}（一）全局作用域{alert type="success"}直接编写在script标签中的Js代码，都在全局作用域全局作用域在页面打开时创建，在页面关闭时销毁在全局作用域中有一个全局对象window（代表的是一个浏览器的窗口，由浏览器创建，可以直接使用）在全局作用域中，创建的变量都会作为window对象的属性保存在全局作用域中，创建的函数都会作为window对象的方法保存全局作用域中的变量都是全局变量，在页面的任意部分都可以访问的到{/alert}function fun(){ var a = 123; } fun(); console.log(a);//报错 var a = 10; var b = 20; var c = "hello"; console.log(window.c);//输出hello function fun(){ console.log("我是fun函数"); } window.fun();//与下面效果相同 fun();1、变量的声明提前{alert type="success"}使用var关键字声明的变量，会在所有的代码执行之前被声明（但是不会赋值）但是如果声明变量时不使用var关键字，则变量不会被声明提前{/alert}var a; console.log("a = "+a); var a = 123;2、函数的声明提前{alert type="success"}使用函数声明形式创建的函数function 函数(){},它会在所有的代码执行之前就被创建， 可以在函数声明前调用函数使用函数表达式创建的函数，不会被声明提前，所有不能在声明前调用{/alert}var fun();//已经赋值 fun();//输出我是fun函数 var fun2;//没有赋值 fun2();//报错，不存在fun2()函数 //函数声明，会被提前创建 function fun(){ console.log("我是fun函数"); } //函数表达式，不会被提前创建 var fun2 = function(){ console.log("我是fun2函数"); }（二）函数作用域（区域作用域）{alert type="success"}调用函数时创建函数作用域，函数执行完毕后函数作用域销毁每调用一次函数，就会创建一个新的函数作用域，他们时=是互相独立的在函数作用域中可以访问到全局作用域的变量，在全局作用域无法访问到函数作用域的变量当在函数作用域操作一个变量时，它会先在自身作用域中寻找，如果有就直接使用，如果没有就向上一级作用域中寻找，直到找到全局作用域，如果全局作用域也没用就会报错在函数中想要访问全局域中的变量可以使用window对象{/alert}var a = 10; function fun(){ var a = "我是函数中的变量a"; var b = 20; //console.log("a = "+a); function fun2(){ console.log("a = "+window.a)； } fun2(); } fun(); console.log("a = "+a);在函数作用域中也有声明提前的特性{alert type="warning"}使用var关键字声明的变量，会在函数中所有代码执行前被声明(不会被赋值)函数声明也会在函数中所有代码执行前被创建在函数中不使用var声明的变量都会变成全局变量定义形参就相当于在函数作用域中声明了变量{/alert}function fun3(){ fun4(); console.log(a); var a = 35; function fun4(){ alert("我是fun4"); } } fun3(); var c = 33; function fun5(){ console.log("c = "+c); var c = 10; //没有var关键字，则会变为全局变量，相当于window.d d = 100; } fun5(); //在全局输出c console.log("d = "+d); //定义形参就相当于在函数作用域中声明了变量 function fun6(e){ alert(e); } fun6();四、debugalert(c); var a = 10; var b = "hello"; c = true; function fun(){ alert("hello"); } var d = 35;使用浏览器F12检查功能进行debug检查