HTML,CSS,JavaScript知识点-CSDN博客

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

HTMLCSSJavaScript知识点

HTML篇

HTML是超文本标记语言。文件以.html结尾。

Hello,HTML。

常用的工具:

标题:

     <h1>一级标题</h1>
     <h2>二级标题</h2>
     <h3>三级标题</h3>
     <h4>四级标题</h4>

image-20230911082525518

无序列表和有序列表

    <ul> <!-- 无序列表-->
       <li>天气</li> 
       <li>天气1</li> 
       <li>天气2</li> 
       <li>天气3</li> 
       <li>天气4</li> 
       <li>天气5</li> 
    </ul>
    <ol><!-- 有序列表-->
        <li>天气</li> 
        <li>天气1</li> 
        <li>天气2</li> 
        <li>天气3</li> 
        <li>天气4</li> 
        <li>天气5</li> 
    </ol>
    <dl><!-- 自定义列表-->
        <dt></dt>
        <dd></dd>
        <dt>男1</dt>
    </dl>

段落标签和文本标签

    <!--段落标签-->
    <P>这是一个段落</P>
    <!--修饰一个文本-->
    <span>这是一个文本</span>

表单和按钮:

border属性为表格添加一个边框样式。

cellpacing 设置单元格间距

    <form action="">
        Input account<input type="text" name="account"><br>
        Input password<input type="password" name="password"><br>
        <input type="radio" name="sex" value="1" checked><!--当加上checked时默认选择-->
        <input type="radio" name="sex" value="2"><br>
        <input type="checkbox" name="check" value="1">1
        <input type="checkbox" name="check" value="2">2
        <input type="checkbox" name="check" value="3">3
        <br>
        <select>
            <option value="1">option1</option>
            <option value="2">option2</option>
            <option value="3">option3</option>
            <option value="4">option4</option>
        </select>
        <br>
        <textarea row="200" cols="50">
            Please input text
        </textarea>
        <br>
        <input type="submit" name="submit">
        <button name="save">save</button>
    </form>

image-20230911091625806

input属性中有placholder属性可以添加提示信息。

插入图片

<div style="background-image: url(../img/1wRYvu3TIo7EVQZ.jpg);" class="class1">
</div>
<style>
        .class1 {
            background-size: cover;
            height: 100%;
            width: 100%;
            position: fixed;
            background-repeat: no-repeat;
            background-attachment: fixed;
            /* 水平向上移动 */
            background-position: 0 -60px;
        } 
</style>

链接:

            <!-- 当前的老窗口打开 -->
            <a href="www.baidu.com" target="_self">点击进入</a>

            <!-- 在一个新的从窗口打开 -->
            <a href="www.baidu.com" target="_blan ">点击进入</a>

布局(合并单元格):

行合并:

        <tr>
            <td rowspan="2"><b>崔颢</b></td>
            <td>黄鹤楼</td>
            <td><a href="">查看诗文</a></td>
            </tr>

列合并:

            <tr style="background-color: rgb(211, 207, 121);">
                <td colspan="3" align="right"><a href="">查看更多崔题</a></td>
            </tr>

成品:

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div style="text-align: center;">
        <h2>效果图</h2>
        <table border="1" cellpadding="10" height="50" width="800" align="center" cellspacing="0">
        <tr>
            <td rowspan="2"><b>崔颢</b></td>
            <td>黄鹤楼</td>
            <td><a href="">查看诗文</a></td>
            </tr>
            <tr>
                <td>《题沈隐侯八咏楼》</td>
                <td><a href="">查看诗文</a></td>
            </tr>
            <tr style="background-color: rgb(211, 207, 121);">
                <td colspan="3" align="right"><a href="">查看更多崔题</a></td>
            </tr>
        </table>
    </div>
</body>

</html>

image-20230911164806439

CSS篇

CSS层叠样式表。实现内容和样式分离。

选择器:

  • 类选择器:
<style>
.style1{
   text-align:center
}
</style>
<p class = "style1">这是一个段落</p>
  • id选择器:
<style>
#style1{
    text-align:center
}
</style>
<p id="style1">这是一个段落</p>
  • 元素选择器:

    让整个页面的相应元素采用该样式

<style>
p{
    text-align:center
}
</style>
<p id="style1">这是一个段落</p>
  • 通配符选择器:

    让这个页面中的所有标签都执行该样式

<style>
*{
    margin: 0;  //外间距
    padding: 0;  //内间距
}
</style>
<p id="style1">这是一个段落</p>

CSS中常用的修饰:

{
    font-family: 字体的类型(楷书...)
    font-size: 字体的大小
    font-style: 字体的形状(正斜)
    font-weight: bolder 字体的加粗
    text-decoration: underline 下划线
}

样式引入的方式有三种

内部样式

通过在html文件中写入style标签将样式写在改标签内

<style>
a{
	
}
</style>
外部样式

专门新建一个css文件然后通过html文件中的link标签引入

<link rel="stylesheet" href="./css/index.css">
行内样式标签内样式

通过标签的style属性写入样式

<div style="height:200px;background:red"></div>

当三种方式向同一个标签写入相同的样式但是样式值不一样这个时候行内样式优先显示其次内部样式再其次外部样式

盒子模型:

image-20230912162834503

布局:

浮动布局

浮动布局是使用css中提供的一个叫做float的样式来完成页面布局的一种布局方式相较与之前的table布局它存在的优势就是可以很好的利用到标签的语义去标记内容不会像table中只有单元格标签这种单一出现可以很好的帮助我们实现SEO的优化

简单来说

float可以快速的将块元素进行左右布局的排列需要进行左右布局的盒子每一个都需要给上一个float样式但是float也会带来一些问题

脱流

当一个元素被赋予了float样式之后这个元素会脱离当前文档流

文档流

所谓文档流我们可以理解成是一个文档对于其内部的内容的表现形式的约束而html文档的内容也就是标签元素的表现形式进行了约束

脱离标准文档流

元素不再受当前文档流的表现形式的约束也就是说脱流的元素不会再受到标准文档流当中对于元素显示类型的约束那么块元素脱流之后就不会再受块元素独占行的表示形式的约束即然不再独占行那么就只有分享行了

脱流元素的去向

元素我们可以理解成就是一个数据数据这个东西一定需要一个存储空间不然数据是无法长久持续的但是我们现在可以看到给了浮动的元素依然还是可以在页面上正常显示的我们认为脱离了标准文档流的元素会进入到浮动文档流当中进入到浮动文档流后就直接分享行后续继续进入当浮动文档流的元素就会挨个并排排放直到一行排满另起一行

脱流会造成父元素高度崩塌

当我们的子元素受浮动影响脱流之后原本有子元素撑起的父元素的高度会丢失父元素高度的丢失会造成父元素的兄弟元素跟着一起发生位置导致整体布局崩塌

清浮动

我们有一个专门用来清浮动的样式 clear:both但是我们并不会使用这个样式来清除浮动因为它会造成一个问题会凭空造就一个空标签出来所以不用

现在我们采用如下方式

.clear{
    overflow: auto;
}

将以上样式赋予到给了浮动样式父元素上来清除子元素上的浮动

定位布局

使用position实现定位布局定位布局分为多种方式我们先看以下三种

绝对定位absolute

决定定位会造成元素脱流与上面的浮动一样也会造成元素不受标准文档流的约束也就是说会丢失块元素宽度100%的样式但是依然可以通过样式来设置宽高也可以通过内容来撑宽高

相对定位relative

相对定位不会造成元素的脱流元素依然在标准文档流内所以不会影响布局结构但是一般我们并不会使用相对定位来进行位置偏移更多的时候是为了使用z-index或者去限制决定定位的定位范围

应用点

实际工作中我们并不太会直接使用绝对定位或者相对定位当我们需要通过定位来移动布局元素的时候我们会采用一种叫做父相子绝的方式来使用通过这种方式我们可以将绝对定位的定位原点修改成父元素的大小范围内并且给父元素设置一个固定尺寸来解决决定定位因为无法确定浏览器窗口宽度而造成的视觉上的偏移位置不正确的清除

固定定位fixed

固定定位对元素带来的影响与绝对定位一样都会脱流但是固定定位的定位范围是永远都固定在浏览器窗口上的所以随着浏览器窗口的滚动固定定位的元素也会跟着一起滚动

当我们使用定位样式之后可以使用如下几个样式

left从左向右偏移

right从右向左偏移

top从上向下偏移

bottom从下向上偏移

z-index修改定位元素之间的叠加的前后关系的取值范围9999 至 -9999

背景:

backgroud时一个复合样式。

backgroud-color 背景颜色会默认铺满整个内容区域。

backgroud-image:url(路径) 背景图片通过路径将一张图片作为背景图片引入。

backgroud-position 背景图片定位。

backgroud-repeat 背景图片是否铺满。

backgroud-size 控制背景图片的尺寸

JavaScript篇

变量标识符var

变量本质上来讲是一个容器一个数据的临时储存空间这个储存空间是由内存ram提供的所以当我们的程序越大可能会需要占用的内存空间就越大所以我们经常会发现当我们电脑打开多个程序的时候会变的越来越卡的原因之一就是这个

在ES5.1中我们使用一个叫做var关键字来顶一个变量

var 变量名;

变量的命名是有要求的不要随便取名整个取名过程有一个大前提就是经量表意

1、以字母或者_或者$开头不能使用数字开头后面可以添加任意字母或者数字下划线美元符号

var a;
var _a;
var $a;
var 1a;   //错误
var a-b;  //错误

2、变量名不能是系统的关键字或者保留字

3、变量名一定要做到一定的规范

见名知意我们看到这个变量名就大概知道里面装的是什么

约束规范ES的变量名采用小驼峰写法如果你的名字是一个组合单词第一个单词首字母小写后面单词的首字母大写

变量是可以批量声明的

var age,name,sex;

变量的赋值

变量第一次赋值也交变量的初始化

var age;
age = 10;

//也可以批量声明然后挨个赋值
var age,name,sex;
age = 10;
name = "zhangsan";
sex = "女"

上面的我们完成变量的赋值

1、变量的赋值使用 = 来完成

2、变量应该先声明再赋值

变量里面储存的数据是可以被替换掉的也就是可以进行二次赋值

var age,name,sex;
age = 10;
age = 20;

上面我们执行了一个二次赋值的过程后面赋的值会把前面赋的值替换掉

现在我们是把声明+赋值分成两步来完成的我们可以简化以下

var age = 19;   //变量初始化

JavaScript中的数据类型

在js中我们通过不同的需求可能会使用到一些不同的数据这些数据都需要进行一个类型上的描述不同类型的数据在处理方式和过程上都会有一些不一样

在js中数据类型可以分成两个大类

基础数据类型原始数据类型
  • 字符串String
  • 数字Number
  • 布尔 Boolean
  • 空类型 null
  • 未定义类型 undefined
应用数据类型复杂数据类型
  • object
字符串类型 String

字符串类型是js中最常见的数据类型它使用引号来包裹所有被引号包裹的我们都可以看作是一个字符串

字符串类型的最大特征就是在执行过程中只会按字面量来进行输出

var userName = "今天天气不错";
var age = "18"

注意

不管单引号还是双引号只要被引号包裹住就是字符串但是有一个情况如果出现了单双引号嵌套的情况单引号不能包裹双引号双引号可以包裹单引号

var txt = "爸爸说'你今天没有挨打吧',我说'是感觉今天好像少了点什么'"
数字类型Number

数字类型在js中是表示数字的数据最常见的就是我们的10进制数

var age = "18"
var height = 180;
var money = -2000;

在其他编程语言里面有int、float、double 等等不同的数字类型但是在js里面统一就一个数字类型在js里面是没有这些概念的

数字是有进制的

var a = 100;
var v = 0x100;

在16进制中所有0x开头的都是16进制赋值完成之后会把后面的10进制数转换成16进制

在Number类型中我们有一个特殊的数字类型NaN

NaN是一个非常特殊的数字它的全称 Not a Number 所有无法用阿拉伯数字表示的Number类型数字都用NaN表示

布尔类型

布尔类型的值在大多数计算机语言中都是具备的这个类型的数据只有两个分别是true和false

var isBoy = false;
var isGirl = true;
未定义类型undefined

未定义类型在js中表示定义了变量但是不赋值这个时候变量里面装的就是未定义类型该类型下只有一个值undefined

空类型null

null与undefined有一点点类型但是它是作为描述不存在没有无这些概念的一个值该类型就一个值null

var a = null;

JavaScript的弱类型机制

刚刚我们学习了5中基础数据类型那么一个变量如果定义的时候赋值了一个数据而数据都有自己的类型那么我们后面可以不可以再次改变这个数据类型

var a = "haha";
a = 100;

在js当中变量是没有固定的数据类型的变量的数据类型会根据你赋值的数据类型的变化而变化我们赋什么值变量就是什么类型这种变化就是js的弱类型机制

比如说一些强类型语言中在定义变量的时候就需要提交数据类型的声明

int a;
float b;
long c;
string d;
boolean e;

强类型语言在定义变量的时候必须要声明变量的数据类型比如java、c#、c++等等

弱类型语言就不需要定义变量的时候定义数据类型比如JavaScript中的var

即然变量的数据类型是会发生改变的那么我们应该如何知道某一个变量内部的数据类型呢

数据类型检测

在JavaScript中数据类型的检测我们使用关键字 typeof

var num = 1;
var str = "jaja";
var boo = true;
var und = undefined;
var nul = null;
console.log(typeof num);   //number
console.log(typeof str);   //string
console.log(typeof boo);   //boolean
console.log(typeof und);   //undefined
console.log(typeof nul);   //object 注意null检测的类型为object不是null

typeof使用方式

typeof 变量名

还有另外一种方式

typeof(变量名)

数据类型转换

JS里面5种原始数据类型是可以相互之间转换的一般情况下我们会对字符串、数字、布尔来进行转换

字符串转十进制数字

这个转换是有条件的它必须是数字字符串

var a = "123";
var b = "abc123";
var c = "123abc";
var d ="123.123";
var e = "-123";
var f = "hello";

上面我们声明了6个变量都赋值了字符串进去然后我们通过转换方法来看下执行结果

string转number有三种方法

1、Number()

var a1 = Number(a);
var b1 = Number(b);
var c1 = Number(c);
var d1 = Number(d);
var e1 = Number(e);
var f1 = Number(f);

代码分析

经过上面的实验我们发现Number方法只能转换合法的数字字符串当字符串转换的时候字符串中包含了非数字的字符时统一转换成 NaN

2、parseInt()

var a1 = parseInt(a);
var b1 = parseInt(b);
var c1 = parseInt(c);
var d1 = parseInt(d);
var e1 = parseInt(e);
var f1 = parseInt(f);

代码分析

经过上面的转换对比我们得到一个结论parseInt在转换过成中遵循以下两个情况

1、如果字符串是数字和字母的混合在转换过程中对字符串中的字符逐个转换如果一开头就碰到了非数字的字符就直接放弃掉后面字符的转换直接返回一个NaN的结果如果开始是数字那么就逐个转换直到碰到非数字字符停止转换把后面未转换的抛弃掉

2、如果转换的数字有小数点直接把小数点后面的数字全部抛弃不会做四舍五入

3、parseFloat()

这个方法和上面的parseInt的转换机制是一样的除了针对小数点后面数字的保留以外

总结
  • Number方法的转换是一个整体转换它必须整体是一个合法的数字字符串而perseInt和perseFloat是逐个字符转换
  • Number在转换的时候对原数据类型是没有要求的但是parseInt和parseFloat必须是字符串才行

布尔转十进制数字

var a = true;
var b = false;

var a1 = Number(a);   //1
var b1 = Number(b);   //0

null和undefined转十进制数

var a = null;
var b = undefined;

var a1 = Number(a);    //0
var b1 = Number(b);    //NaN

其他类型转换字符串

在js里面所有的数据类型都可以转换成字符串并且转换过程最简单直接加引号

var a = 123;
var b = true;
var c = 123.123;
var d = null;
var e = undefined;

上面5个变量就是我们除了字符串以外的4个原始数据类型这个数据都可以转换成字符串的并且方法很多

1、String()

使用String方法进行转换之后以上5种情况的结果均按照字面量来进行转换

2、通过加法计算符来进行转换隐性转换

var a = 5 + "";

代码分析

这种做法是利用了 + 一个特性当 + 的左右变量其中有一个是字符串类型的数据 + 会隐性转换另外一边的数据为字符串类型然后 + 会作为字符串连接符将 + 两边的字符串进行一个合并而我们这里右边设置的是一个空字符串根据上面我们所说的特性+ 会把左边的数字5转换成一个字符串然后拼接上右边的空字符串从结果上来讲得到了一个字符串5

3、toString()

var a = true;
var a1 = a.toString();  //"true"

注意

这个方法不能转换null和undefined控制台会报错要转换null和undefined只能通过String()

★★★其他类型转布尔

这个转换过程在js中比较麻烦因为布尔值在后面的语句的流程控制当中使用非常频繁

在js我们要让其他类型转换成布尔类型使用 Boolean()

var a = 1;
var b = 0;
var c = "";
var d = "123";
var e = null;
var f = undefined;
var g = NaN;
var h = 123;
var i = "true";
var j = "false";

上面的变量基本覆盖了所有的原始数据类型和可能出现的组合并且还有一些特殊值通过Boolean转换一下

var a1 = Boolean(a);   //true
var b1 = Boolean(b);   //false
var c1 = Boolean(c);   //false
var d1 = Boolean(d);   //true
var e1 = Boolean(e);   //false
var f1 = Boolean(f);   //false
var g1 = Boolean(g);   //false
var h1 = Boolean(h);   //true
var i1 = Boolean(i);   //true
var j1 = Boolean(j);   //true

结论:

在整个js体系中能够被描述成false的只有6个值这个6个值是可以明确为false的分别是 0空字符串falseNaNnullundefined

流程控制语句:

if语句

if也叫判断语句/条件语句/分支语句 它会根据一个条件来决定执行相应的代码块控制代码流程的走向它使用关键字 if else

if(判断条件){
	条件成立时执行的代码
}else{
	条件不成立时执行的代码
}

举例

var money = 10;
if(money == 0){
    console.log("我要找人蹭饭")
}else{
    console.log("吃大餐")
}

根据上面的例子我们可以得到一个结论

if(一可以得到布尔值结果的表达式){
	判断条件为true时执行的语句
}else{
	判断条件为false时执行的语句
}

但是我们要注意一点因为JS是弱类型语言执行的是弱判断所以if后面的条件可能并不是一个布尔值如果不是则通过Boolean方法转换

var money = 0;
if(money){
    console.log("吃大餐")
}else{				
    console.log("我要找人蹭饭")
}

上面的代码最终输出的是 我要找人蹭饭 因为 Boolean(money)转换为false所以条件不成立执行else后面的语句

结论

if(可以得到任意数据类型结果的表达式){
	判断条件为true时执行的语句
}else{
	判断条件为false时执行的语句
}

场景 如果明天是晴天我们就去郊游如果明天下雪我们就放假否则我们明天来教室上课

var weather = "晴天";
if(weather == "晴天"){
    console.log("郊游")
}else if(weather == "下雪"){
    console.log("放假")
}else{
    console.log("上课")
}

小练习

当时间在0-8之间包含8点输出上午好8-12点的时候包含12点输出中午好12-18点的时候包含18点输出下午好,18-24点之间的时候输出完好

提示结合逻辑运算编写判断条件

var time = prompt();
if(time > 0 && time <= 8){
    console.log("上午好");
}else if(time > 8 && time <= 12){
    console.log("中午好")
}else if(time > 12 && time <= 18){
    console.log("下午好")
}else if(time > 18 && time <= 24){
    console.log("晚上好");
}else{
    console.log("请输入正确时间")
}

for循环语句

for是作为启动循环功能的关键字它可以让程序在某一个条件下不停的执行下去

场景

现在小明同学要帮老师去搬砖要搬10块砖但是小明的力气很小只能一块一块的搬搬完就可以去吃饭了

针对上面场景我们可以分析出来一下几个数据

1、小明从第一块砖开始搬

2、一共要搬10块没有达到10块不能停下来

3、小明力气比较小只能一次搬1块

for(初始值;循环条件;自变量){
	//代码体
}

现在通过以上的语法结合上面的场景完成我们的代码用编程的思维来帮助小明板砖

//初始值小明从第一块开始搬所以我们需要设置一个初始量来记录板砖的数量
//循环条件小明需要搬10块转不搬完不让休息
//自变量小明力气小只能一次搬一块
for(var i = 1; i <= 10; i++){
    console.log("小明同学正在板砖现在搬到了第" + i + "块")
}

代码分析

上面的代码循环执行了10次那么在循环执行得到10次里面代码到底是怎么执行的

通过断点分析我们发现循环语句在执行的时候它所循环的代码都会经过下面三个部分

1、判断循环条件是否成立

2、执行代码体

3、自变量变化

场景修改小明给老师搬砖要搬10块砖之前已经搬了3块现在从第4块砖开始每次搬1块

for(var i = 4; i <= 10; i++){
    console.log("小明同学正在板砖现在搬到了第" + i + "块")
}

场景修改小明给老师搬砖要搬6块从第1块开始

for(var i = 1; i <= 6; i++){
    console.log("小明同学正在板砖现在搬到了第" + i + "块")
}

场景修改小明给老师搬砖要搬10块砖从第1块开始小明练出来了力气大了每次可以搬2块砖

for(var i = 1; i <= 10; i += 2){  //i = i + 2;
    console.log("小明同学正在板砖现在搬到了第" + i + "块")
}

循环倒序

for(var i = 10; i > 0; i--){
    console.log("小明同学正在板砖现在搬到了第" + i + "块")
}

while循环

while也是一种循环它与for一样都是前测试循环它和for循环差不多语法如下

while(循环条件){
	// 循环体
}

注意

所以的循环都需要基初始值循环条件自变量

var i = 1;
while(i <= 10){
    console.log(i);
    i++;
}

注意

while循环的循环条件不一定非要是一个布尔值

var i = 10;
while(i){
    console.log(i);
    i--;
}

do…while循环

do…while 是一个后测试循环先执行循环体然后再判断循环条件是否成立

do{
	//循环体
}while(循环条件)

运算符

一元操作符

只能操作一个值的操作符我们叫做一元运算一元操作符一元操作在js中是比较简单的一个元操的结果一定是一个Number类型

递增递减运算
var a = 3;
var b = 3;

b++;   // b = b + 1;
a--;   // a = a - 1;

上面的计算过程我们可以的到b为4a为2所以我们认为递增或者递减运算就是在原有的数据基础上执行一个+1 或者 -1 的操作

使用递增或者递减运算的时候运算符出现的位置也会影响计算结果

**思考**放在前面和放在后面的区别

var a = 3;
var b = 3;
a++;  //a = a + 1 先调用变量a然后执行一个加法运算然后把运算结果赋值
++b;  //b = b + 1 执行一个加法运算然后把运算结果赋值然后调用一遍变量b
console.log(a)   //4
console.log(b)   //4

上面的代码经过运算之后我们发现两个变量a和b都是4难道符号在前在后没有区别

我们把执行过程稍微改一下

var a = 3;
var b = 3;
console.log(a++);  //先调用一遍变量a在控制台输出然后执行了一个加法运算最后再把运算结果赋值给a
console.log(++b);  //先执行了加法运算然后把结果赋值最后再调用一遍在控制台输出

简单理解

符号在后先使用这个变量使用完之后再去改变这个变量

符号在前先改变这个变量再去使用这个变量

练习 根据上面的特点来完成一个小练习

var a = 11;
var b = 12;
var c = 13;
a++;  //12
++a;  //13

var d = a++ + ++b + c++ + ++a;
//      13  +  13 + 13  + 15;
//问a,b,c,d的值各为多少
// a:15
// b:13
// c:14
// d:54
注意

递减运算也是一样的规则只不过是 -1 不是 + 1

特殊类型值的递增递减运算
var a = "1";        //a++ 2
var b = "hello";    //b++ NaN
var c = "";         //c++ 1
var d = true;       //d++ 2
var e = false;      //e++ 1
var f = null;       //f++ 1
var g = undefined;  //g++ NaN
var h = NaN;        //h++ NaN
递增递减操作原则

1、一元操作符的结果一定是Number类型

2、如果是非数字类型的数据执行递增或递减运算则先将这个值进行Number的操作进行转换

3、NaN不参与运算即使参与了结果也一定是NaN

4、符号在后先使用自己再改变自己符号在前先改变自己再使用自己

一元加减运算

一元加减运算是js中比较特殊的运算它相当于执行Number方法的类型转换它的结果也是一定是Number类型

var a = "01";  
a = +a;         //1
var b = "1.1";
b = +b;         //1.1
var c = "z";
c = +c;         //NaN
var d = false;
d = +d;         //0
var e = 1.1
e = +e;         //1.1
var f = NaN
f = +f;         //NaN
var g = null;
g = +g;         //0
var h = undefined;
h = +h;         //NaN

以上是一元加法运算一元减法其实也是一样的只不过把转换结果变为负数

一元加减法的操作原则

1、结果一定为Number类型

2、非数字类型的数据通过Number转换

3、NaN不参与运算

4、如果是一元减法则是通过Number转换再乘以 -1

加法运算

加法操作符使用 + 来表示加法运算的结果不一定是Number类型

因为JS是一个弱语言所以在执行加法运算的时候不一定是数字相加还有可能是其他类型相加

console.log("hello" + "world");
console.log(1 + 2);
console.log("1" + 2);
console.log(true + 1);
console.log(true + "1");
console.log(NaN + 1);
console.log(NaN + "1");
console.log(1 + undefined);  
console.log("1" + undefined);
console.log(true + true);
console.log(null + true);
console.log(true + undefined)
加法运算操作原则

1、如果执行加法的时候有字符串则结果一定是一个拼接型的字符串

2、NaN不参与运算如果参与计算结果一定为NaN

3、对于非数字类型的数据进行加法运算的时候则使用Number方法进行转换

隐藏规则在加法运算中字符串是老大NaN是老二加法字符串优先

小练习

console.log(1 + "2" + "2");    //"122"
console.log('1' + 2 + 3);      //"123"
console.log(1 + +"2" +"2");    //"32"

减法运算

减法操作符使用 - 表示减法运算的结果一定是Number类型

2 - 1         //1
"2" - 1       //1
"2" - "1"     //1
"2" - true    //1
2 - false     //2
1 - null      //1
2 - undefined //NaN
null - true   //-1
"a" - 1       //NaN
"a" - "b"     //NaN
"" - 1        //-1
"" - NaN      //NaN
减法操作原则

1、减法运算一定会得到Number类型的结果

2、NaN与任何数相减都是NaN

3、如果执行的减法不是数字则通过Number方法做隐式转换

乘法运算

乘法运算符 * 表示它的结果与减法操作保持一致

除法运算

除法运算符 / 表示它的结果与减法保持一致

除法中有个特殊情况

console.log(2 / false);    //Infinity
console.log(1 / null);     //Infinity

取余取模运算

取模运算使用 % 符号表示它的结果也一定是number类型也遵守和减法操作原则

console.log(2 % false);    //NaN

逻辑运算

逻辑非运算

逻辑非运算使用 作为运算符执行的结果是把既有的运算结果进行反向输出非真即假非假即真运算结果一定是一个布尔值

举例

var a = true;
var b = !a;

因为JS是弱语言所以在逻辑运算中不一定参与的运算的是布尔类型的数据有可能是其他类型

逻辑非操作原则

1、结果一定是布尔值

2、非真即假非假即真

3、如果操作的值不是布尔类型则通过Boolean去转换

4、有哪些能明确表示为false的值一定要记住

逻辑与运算

逻辑运算使用 && 来表示执行的是一假则假全真为真的原则它的结果不一定是布尔值

举例

var a = true && false  //false
var b = true && true   //true
var c = false && false //false
var d = true && false && true  //false

因为JS是弱语言所以在运算过程中参与运算不一定是一个布尔值

console.log(true && 123);        //123
console.log(true && "" && 123);  //“”
console.log(123 && "abc");       //"abc"
逻辑与操作原则

1、它的结果不一定是布尔值

2、执行所谓的“逢假则假全真为真”的操作

3、短路原则当一个表达式如果得到false的结果就不再向后运算了然后当前为false的表达式的计算结果为逻辑与运算的结果如果没有短路在执行过程中没有碰到任何一个表达式的执行结果可以转换为false就以最后一个表达式的执行结果为逻辑与运算的结果

4、当逻辑与运算中的表达式的运算结果不为布尔值的时候我们执行Boolean方法来转换决定是否继续执行

5、明确哪些是可以作为false条件的数据

逻辑或运算

逻辑或运算的操作符 || 表示执行的是一真全真跟逻辑与正好相反结果也不一定是布尔值

var a = true || false
逻辑或操作原则

1、结果不一定是布尔值

2、执行所谓“一真全真”

3、短路原则与逻辑与运算相反

4、当逻辑或运算中的表达式的运算结果不为布尔值的时候我们执行Boolean方法来转换决定是否继续执行

5、明确哪些是可以作为false条件的数据

小练习

true || "" && NaN        //true

123 || !"" || false      //123

123 && NaN || null      //null

"abc" || 123 && NaN     //"abc"

null || 123 && undefined  //undefined

当逻辑运算进行混合运算的时候就需要考虑类似四则运算中先乘除后加减的情况

注意

逻辑运算先非再与、最后或

比较运算

比较运算的运算结果一定是布尔值

因为JS的弱语言特性在比较运算中不一定运算的过程中只有数字

运算符
>   大于
<   小于
>=  大于等于
<=  小于等于
==  等于
=== 完全等于
!=  不等于
!== 完全不等于

比较运算的一个特殊情况

运算双方不是数字这个时候比较运算会根据ASCII码表的值进行大小比较

函数:

函数的定义

函数的定义方式非常多目前我们只看一种标准方式语法如下

function 函数名(参数,...){
	函数体
}

注意点

1、关于函数名参照标识符的规范

2、函数体函数的代码体里面可以是任意的多条语句

3、后面的大括号不能省声明一个函数出来就必须要有函数体

function sayHello(){
    console.log("hello");
}

上面就是一个函数的声明这个过程我们也叫封装了一个方法

函数的其他声明方式

var 函数名 = function(){

}

具体写法

var sayHello = function(){
    console.log("hello");
}

注意

上面两种声明方式看似一样实际是有区别的

abc();
function abc(){
     console.log("hello abc")
}

def();  //这个会报错
var def = function(){
 console.log("hello def");
}

通过第一种方式声明的函数可以在定义之前调用而通过var定义的函数在定义之前调用会报错

匿名函数:

var multiply = function(x, y) {
  return x * y;
};

递归函数:

function abc(){
    abc();
}

函数的调用

函数定义好之后不会自己执行它需要经过调用才会被执行函数的调用时通过函数名来完成的语法如下

函数名()

注意

函数的实际调用过程中我们需要注意函数名与后面的小括号实际上分别指代两个操作

function test(){
	console.log("a")
}
test()  //调出函数体中所包含的代码并执行
test    //调出函数但是不执行

代码分析

如果只写函数名不写后面的小括号我们会发现函数体内的代码并没有被执行也没有报错原因在于没有写后面的小括号我们可以把小括号理解成一个函数的立即执行符前面的函数名负责调出函数体中的代码后面的小括号负责执行
也就是说我们可以把调用函数的语法理解成由两个部分组成分别是调函数名和用小括号两个部分来看

函数的参数

现在有如下情况

var userName;
function sayHello(){
    console.log("大家好我叫" + userName);
}
userName = "张三"
sayHello();
userName = "李四"
sayHello();
userName = "王五"
sayHello();

当我们调用sayHello的时候我们可以根据变量userName去动态改变打印的结果

这个时候userName的变量定义在函数体外如果定义在函数体内我们无法多次赋值同时定义在函数体内的变量我们叫做局部变量这种局部变量无法跨域使用声明在函数体外的变量我们可以叫做全局变量全局变量可以在任意的函数中调用

引入参数使用让函数变的更灵活

function sayHello(name){
    console.log("大家好我叫" + name);
}
// userName = "张三"
// sayHello();
// userName = "李四"
// sayHello();
// userName = "王五"
// sayHello();
sayHello("张三");  //name参数的值被赋值为张三
sayHello("李四");
sayHello("王五");

有函数的引入函数的作用的灵活性会有很大的提升

形参和实参

形参形式参数指的就是在函数声明的时候在小括号里面写的参数名

实参实际参数调用函数的时候小括号里面写的值

function add(a,b){
    console.log(a + b);
}
//上面的函数中a和b就是形参没有具体的值也没有具体的类型
add(4,5)
//在调用过程中给a和b赋值了实参现在的4和5就是a和b的实参

也可以是以下情况

var x = 5;
var y = 7;
function add(a,b){
    console.log(a + b);
}
add(x,y);

这个时候xy就是add函数的实参因为x,y中是有实际的值

通过这个调用add的时候实参x赋值给了a实参y赋值给b

函数的形参与实参是没有必要形参一一对应的关系

add(100);
add(10,20,30)

函数的重载

函数的重载指的是在定义的时候它的函数名相同而函数的参数个数不同同时参数的类型也不同这个时候同名的函数就叫做函数重载overload

javascript函数中不存在重载只有强语言才有重载

function add(a,b){
	console.log(a + b)
}

function add(a,b,c){
	console.log(a + b + c)
}

这个时候我们看到函数名相同但是的函数的参数个数不同我们的重载是根据参数的个数和参数的类型来决定的但是在JavaScript当中这两点都无法实现

1、js是弱类型语言变量在没有赋值之前都是undefined所以不能通过类型区别

2、js的函数中的形参和实参没有必要形成一一对应的关系这个也无法通过参数的个数去区别

所以JS当中不存在重载那么当出现同名的时候会发生覆盖

返回值

函数的返回值是指函数将内部某些值返回到函数体外的一个操作使用 return 关键字实现js中的每个函数都可以有返回值

举例

function abc(){
    return "hello"
}
var x = abc();

这个时候abc函数会一个返回值 “hello” 然后变量x接收了这个abc函数的返回值所以x的值就是“hello”

function add(a,b){
    var c = a + b;
    return c;
}
var y = add(10,20);

这个时候变量y接收add函数的返回值结果为30

关于return关键字

return是把函数内的值返回到函数外使用同时一个函数碰到了return就是跳出当前函数return后面的代码不再执行

function add(){
    var a = 10 + 20;
    return ;
    console.log(a);
}

return可以打断函数的执行所以后面的console.log(a) 无法被执行

注意

如果不需要返回值但是依然使用了return这个时候return就单纯当作一个函数打断的操作来执行如果有返回值那么return在把值返回到函数外同时还会打断函数执行

递归函数

如果一个函数在内部又调用了自己那么这个函数我们就叫做递归函数

递归函数是可以通过循环来演示的所以我们先看一个循环

//假设我们要求1-10之间整数求和
var num = 0;
for(var a = 1; a <= 10; a++){
    num += a;  //num = num + a;
}
console.log(num);

如果我们需要把上面的循环转换成递归来表示首先我们需要弄情况三个东西初始值循环条件、自变量

var num = 0;
var i = 1;

function add(){
    num += i;
    i++;
    if(i <= 10){
        add();
    }
}
add();

练习斐波拉契数列

现在有一个数列排列是这个样子的112358132134 … 问第N位应该是多少

var a = 1;  //前两项
var b = 1;  //前一项
var c;      //当前项
function list(n){
    for(var i = 1; i <= n; i++){
        if(i == 1 || i == 2){
            c = 1
        }else{
            c = a + b;  //完全当前项的计算
            a = b;      //前一项变成前两项
            b = c;      //当前项变成前一项
        }
    }
    console.log(c);
}
list(20)

递归方式

function abc(n){
    if(n == 1 || n == 2){
        return 1;
    }else{
        return abc(n - 1) + abc(n - 2)
        //          abc(4)         +       abc(3)
        //     abc(3) + abc(2)     +    abc(2) + abc(1)  
        // abc(2) + abc(1) + 1     +       1   +   1
        //   1    +   1    + 1     +       1   +   1
    }
}

变量作用域

我们之前学习的时候通过 var 声明变量这个var定义的变量是没有所谓的”块级作用域“的

var a = 123;   //全局变量
if(true){
    console.log(a);
}
//------------------------------------
{
    var b = 123;
}
console.log(b);
//-------------------------------------
for(var i = 1; i <= 10; i++){
    var c = "haha";
}
console.log(c);

这几个变量其实全都是全局变量这里的大括号并没有形成块级作用域这一点是与其他编程语言不太一样的但是注意一点function的大括号会形成作用域

function abc(){
    var a = 1;   //这是一个局部变量只能在大括号内部调用出了大括号就不能使用了
}
console.log(a);  //这里会报错a找不到

javascript函数二

arguments实参数组

我们讲过形参和实参没有必要形成一一对应的关系形参是不介意你传多个实参的也不在乎你传递的实参是什么类型也就是说我定义两个形参但是我们在调用函数的适合可以传递一个实参或者三个四个更多都是没有问题的

function abc(a,b){
    console.log(a);
    console.log(arguments[0]);
    console.log(arguments[2]);
}
abc(1,2,5)

arguments解析

这个arguments是一个类数组的概念

function abc(){
    console.log(Array.isArray(arguments));
}
abc()  //false

代码分析

通过isArray方法我们判断得到arguments并不是一个数组但是它又可以使用数组的语法

数组与类数组有什么区别

1、数组Array会有数组的方法而arguments是没有的

2、它们都有langth属性和索引而索引和length属性是数组才有的特性

总结

在JavaScript中当一个对象具备数组的特征索引和length但是不具备数组的方法这种对象我们叫做类数组

注意

arguments只能在函数体内使用出了函数体就没用了

立即执行函数

当我们定义好一个函数之后立即执行我们可以把这个函数看做是一个立即执行函数

var userName = "张三";
var x = !function abc(){
    userName = "李四";
    console.log(userName);
    return userName;
}();
console.log(x);

代码分析

上面的立即执行有一个问题它不能返回内部的值到外面

前面的 可以换成 +

函数表达式
var abc = function(){
    var userName = "张三";
    console.log(userName);
    return 123;
}();
console.log(abc);

代码分析

这个时候就不再是一个单纯的函数表达式了因为这个表达式的等号右边的匿名函数现在是一个立即执行的状态

这个时候赋值给abc的就不再是函数体本身了而是函数的返回值

闭包函数

闭包函数简单来说就是函数声明的嵌套也就是在一个函数声明的里面再声明一个函数要理解闭包要先了解变量作用域和JS垃圾回收机制

function a(){
	function b(){
	
	}
}
JS垃圾回收机制

声明再函数体内的变量会在函数执行完毕的瞬间销毁掉

闭包例子

function f(x){
    var a = x;  //局部变量a = 5;
    var b = function(){   //声明函数b
        return a;         //在函数b内部调用a
    }
    a++;     //递增运算 a = 6;
    return b;   //返回函数b的函数体
}
var c = f(5);  // function b(){return 6}

声明在函数体内的变量是局部变量布局变量只能在函数提调用的时候才会被声明出来并且只能在函数体内调用现在我们在外层函数f中声明一个局部变量a又声明了一个函数b并且在其内部调用了外层函数的局部变量a现在会形成一个闭包表现

总结下来要形成闭包

在内部函数里面return外层函数的局部变量在外层函数里面return内层函数的函数体

闭包函数的组用

闭包函数其实就是为了让内部函数调用外部函数的变量然后让外部函数将内部函数的函数体返回出去从而达到可以调用局部变量的目的

为了数据安全性

首先我们先明确一点变量是用来储存数据的同时由于作用域的关系变量又分了局部和全局两种作为全局变量来讲它是运行任何人在任何时候进行访问的那么对于储存在全局变量当中的数据的安全性就会有一定影响而局部变量作为声明在函数体内的变量自身有一个特性当函数执行完毕之后会立即释放掉同时因为作用域的关系局部变量是无法被外部直接访问的那么我们就认为局部变量相比全局变量对于数据的安全性会更好但是又由于会在函数调用结束后立即被释放掉所以导致局部变量无法长时间的储存数据

现在我们即需要局部变量的相对的安全性保障同时又需要局部变量不能在函数执行完毕之后被垃圾回收机制回收掉所以就出现了闭包函数的调用形式这种形式下的函数执行完毕之后其内部的局部变量不会被回收

使用闭包的注意事项

闭包虽然可以解决一些问题但是也会带来一些问题由于闭包会携带外部函数的局部变量所以内层占用是比较大的所以经量少用慎用闭包

1、因为闭包的使用内存里面会一致维持一个变量存在可以用做缓存也可以用作提高数据安全性

2、函数内部的局部变量不会被垃圾回收机制销毁增大内存消耗导致内存泄漏解决方案就是可以使用完之后手动给变量赋值null或者通过delete关键字手动删除

闭包执行

function a(){
	var userName = "zhangsan";
	console.log(userName);
}
a();

上面的代码a代表函数名我们在函数名后面加上小括号就可以执行了所以把上面的代码稍微改下

(function a(){
	var userName = "zhangsan";
	console.log(userName);
})()

这里其实我们可以认为就是一个立即执行函数只不过没有采用或+ 的方式来进行而已

回调函数

回调函数就是把一个函数作为另一个函数的实参传入被当作实参传入的函数我们就叫回调函数

1、当某些功能需要分段执行的时候流水线操作

2、当一个函数的返回值无法返回的时候

function abc(x,y,z){
	var a = x + y + z;
	var b = x - y - z;
	return [a,b];  //如果我们需要把上面的a和b同时返回出去目前来看只能通过数组的方式
}

我们通过回调完成

function abc(x,y,z,callBack){
    var a = x + y + z;
    var b = x - y - z;
    callBack(a,b);
}
function print(_a,_b){
    console.log("三个数的和" + _a);
    console.log("三个数的差" + _b);
}
abc(10,20,30,print);

数组

数组实际上就是一个数据集合

JavaScript当中的数组与其他强类型语言的数组再概念上是有区别的

1、强语言数组会规定当前数组的长度并且数组中所储存的数据类型也是规定死的

2、在JS当中因为是弱类型语言根据弱类型的特征数组的长度与数组所储存的数据类型都没有强制规定

数组的定义

数组分几种方式可以创建

通过 new Array()创建
var arr = new Array();   //创建了一个空数组这个数组里面什么都没有长度为0

这里有一个new关键字这个关键字在后面构造函数中来讲

new Array() 代表创建了一个Array实例数组对象

var arr = new Array(6);   //创建了一个空数组但是这个数组有一个默认的长度为6
var arr = new Array(1,2,3,4,5);  //创建了一个带有12345的数组

注意事项

var a = new Array("a");  //创建了一个数组这个数组包含了字符串a
var b = new Array("2");  //创建一个数组这个数组包含了字符串2
var c = new Array(-1);   //报错
var d = new Array(3.5);  //报错
var e = new Array(-2,-1);//静态化创建

通过 [ ] 的方式创建数组

var arr = [];
var arr1 = [1,2,3,4,5,6];

数组的类型检测

我们检测数据类型的时候使用 typeof

var arr = [1,2,3];
console.log(typeof arr);  //object

这个时候检测出来的类型是object检测结果不标准我们只能知道一个大概后期学习的很多东西通过typeof检测出来的都是object所以我们认为typeof只适合检测原始数据类型

instanceof

instanceof与typeof的区别typeof是直接告诉你检测的数据类型结果而instanceof则是通过关键字的右边设置类型左边设置要检测的数据看是否匹配来给出一个true或者false的结果

var arr = [1,2,3,4];
arr instanceof Array  //true

通过Array.isArray() 来判断

这里是数组专门提供的一个方法来检测当前变量里面是否包含了数组

var arr = [1,2,3,4];
Array.isArray(arr);

数组的取值和赋值

数组的取值与赋值都是通过下标索引来完成索引从0开始一次对应每一个数组中的元素 + 1通过

数组名[索引值]来完成取值与赋值数组里面的值也叫数组元素

arr[0]           //1

arr[3]           //543

arr[5]           //undefined

arr[2] = "hello"
arr[2]           //'hello'
arr[6] = "haha"  //[1, 'a', 'hello', 543, true, undefined, 'haha']

数组的遍历

遍历简单来讲就是把数组中的每一个元素都调用一遍

var arr = [1,"a","23",543,true,undefined];
for(var i = 0; i < arr.length; i++){
    if(typeof arr[i] == "string"){
        console.log(arr[i]);
    }
}

代码分析

我们通过循环的方式将数组中的每一个元素挨个调用然后参与循环体中的判断来决定到底最终在控制台打印哪些数组元素

数组的属性与方法

属性用于描述事物的特征

方法这个对象的概念就是我们之前学过的函数

学习数组其实就是学习数组的属性和方法让我们可以方便的操作数组

1、length属性用与获取数组的长度

var arr = [1,2,3,4,5,6];
var a = arr.length;

2、push() 向当前数组中的最后面添加一个数组元素并返回当前数组的长度

var arr = [1,"a","23",543,true,undefined];			
var x = arr.push("abc");

3、pop() 移除当前数组的最后一个元素并返回这个被移除的元素

var arr = [1,"a","23",543,true,undefined];	
var y = arr.pop();

4、unshift() 向当前数组的前面添加一个元素并返回这个数组的长度

var arr = [1,"a","23",543,true,undefined];	
var z = arr.unshift("123");

5、shift() 移除当前数组中最前面一个元素并返回这个元素

6、concat() 将多个数组进行合组成一个新数组把需要组合的数组作为实参传入并返回新数组原数组不变

7、slice() 截取数组当中的元素返回一个新数组原数组不变

var newArr1 = arr.slice(1,3);  //从索引1的位置开始至索引3结束不包含结束位
var newArr2 = arr.slice(1);  //从索引1开始截取到最后
var newArr3 = arr.slice();  //相当于把数组复制了一份
var newArr4 = arr.slice(1,-1);  //负数代表倒数-1表示最后一个整数理解索引从索引1截取到倒数第2个不包含结束位
var newArr5 = arr.slice(-2,-1);  //相当于从倒数第二个截取到倒数第一个不包含结束位

8、reverse() 将数组元素内部的数组元素反转返回一个新数组原数组改变

9、toString() 将数组转换成字符串返回

10、join() 将数组中的元素用指定的符号隔开然后再转成字符串

12、indexOf() 查找某一个元素再数组中最先出现的位置返回这个元素的索引值如果没有找到返回 -1

13、lastIndexOf() 查找某一个元素在数组中最后出现的位置返回这个元素的索引值如果没有找打返回-1

14、splice() 在指定的位置删除指定个数的元素放入指定个数的元素然后删除的元素组成一个新数组返回

var a = arr.splice(1,2);        //索引值1开始向后数2个删除并返回删除元素
var b = arr.splice(1,0,"haha")  //索引1开始向后删除0个并在索引1的位置添加"haha"并返回删除元素
var c = arr.splice(1,1,"张三")   //索引1开始向后删除1个并在索引1的位置添加"张三"并返回删除元素

特殊情况

arr.splice(1);   //索引1开始删除到最后面
arr.splice(-2);  //倒数第2个开始删除到最后
arr.splice(1,-1);  //数组保持不变
arr.splice(1,"a")  //

数组的高级方法与二维数组

数组的迭代方法

数组的迭代方法也叫数组的遍历方法它有5个遍历方法

所有的遍历方法都有以下特点

1、不能使用break不能使用continue跳过

forEach方法
var arr = [1,2,3,4,5,6];
arr.forEach(function(item,index,_arr){
    console.log(item * 2);
})

上面的代码使用forEach遍历的方法它使用回调函数完成后续操作回调函数接收三个参数

  • item 代表当前遍历的这一项数组元素
  • index 代表当前遍历的这一项数组元素的索引
  • _arr 代表当前正在遍历的数组
map方法

也是一个遍历数组的方法与forEach类似唯一不同的是可以把每次迭代的回调函数的返回值接收下来然后组成一个新的数组

var newArr = arr.map(function(item,index,_arr){
    var x = item * 2;
    return x;
})
filter方法

该方法与map类似它会在原数组中返回符合指定条件的数组元素然后讲这些数组元素组成一个新的数组返回到外面

var filterArr = arr.filter(function(item,index,_arr){
    return item % 2 == 0;
})
every方法

该方法会对数组里面的每一个元素执行遍历回调函数返回一个条件这个条件会生成一个布尔值每一次遍历都会把当前遍历的数组元素参与到这个回调函数中的返回条件中执行并将执行结果转换成布尔最后把每个元素执行的布尔结果再执行一个逻辑与运算

var result = arr.every(function(item,index,_arr){
    return item > 4;
})
some方法

该方法完全参照every方法

reduce方法

语法如下

var result = arr.reduce(function(prev,current,index,_arr){

})

prev 代表前一次回调函数的返回值【这一次回调函数的返回值会作为下次回调函数的prev实参使用】

current 代表当前遍历的值【reduce方法从数组的第二个元素开始】

index 代表当前遍历值的索引

_arr 代表当前正在操作的数组

场景一数组求和

var result = arr.reduce(function(prev,current,index,_arr){
    var num = prev + current;
    return num;
})
reduceRight方法

与reduce方法一样只是它是从右向左遍历

面向对象编程

目前来讲我们有两种比较流行的软件开发思路面向过程面向对象

对象的定义

对象的创建我们可以理解成对象的封装

通过键值对创建对象
var 对象名 = {
	属性名1:属性值1,
	属性名2:属性值2,
	属性名3:function(){
	
	}
}

演示

var stu_xm = {
    name:"小明",
    age:20,
    sex:"男",
    hobby:"打游戏",
    sayHello:function(){
        console.log("hello");
    }
}
var stu_xf = {
    name:"小芳",
    age:18,
    sex:"女",
    hobby:"吃饭"
}

代码分析:

以上我们创建了两个对象里面都包含了name\age\sex\hobby属性记录了当前对象的一些特征同时stu_xm对象中还包含了一个sayHello的方法表示该对象还具备有相应的能力

注意

通过以上方式创建的对象我们叫做字面量对象

如果想在对象内部的方法中调用自己对象内部的属性我们使用this变量这个变量现在先简单理解成写在哪个对象里面这个this变量就指向哪个对象

var stu_xm = {
 name:"小明",
 age:20,
 sex:"男",
 hobby:"打游戏",
 sayHello:function(){
     console.log(this.name + "hello");
 }
}

通过Object方法创建

var obj = new Object();  //该情况下创建的对象为空对象我们需要自己手动去给它添加

添加或删除对象内的属性

添加如果你从某一个对象中调用了一个这个对象不存在的属性对象会给你自动添加上去

var stu_xf = {
    name:"小芳",
    age:18,
    sex:"女",
    hobby:"吃饭"
}
stu_xf.age = 20;       //修改age属性的值
stu_xf.height = 180;   //对象内没有height属性所以添加height属性并赋值180

删除对象的属性使用 delete 关键字

delete stu_xf.sex;   //我们把对象中sex属性进行了删除

使用构造函数创建对象重点

所有的构造函数在调用的时候都是用new关键字来调用并且构造函数的函数名首字母大写

回忆以下创建数组的时候

var arr = new Array();  //这个过程中Array()就是系统预设好的一个构造函数通过new调用创建一个数组对象赋值给arr所以arr就是一个数组对象

现在我们来写一个构造函数

function Student(_name,_sex,_age){
    this.name = _name;
    this.age = _age;
    this.sex = _sex;
    this.sayHello = function(){
        console.log("大家好我叫" + this.name);
    }
}
var stu1 = new Student("张三","男",20);
var stu2 = new Student("李四","女",18);
工厂模式创建对象
function createStudent(_name,_sex,_age){
    var obj = {
        name:_name,
        sex:_sex,
        age:_age,
        sayHello:function(){
            console.log(this.name);
        }
    }
    return obj;
}
var stu1 = createStudent("张三","男",20);

代码分析

通过上面的方式也可以快速的创建对象这个方式就相当于模拟了构造函数的new的过程

构造函数与普通函数的区别

构造函数和普通函数在书写上没有区别关键在于调用上

1、构造函数使用new调用普通函数直接函数名() 调用

2、构造函数的返回值一定是一个对象而普通函数的返回值是根据return来决定

3、普通函数的this它指向的是window对象而构造函数的this指向的是创建的对象

4、如果通过new的形式调用构造函数在执行的时候如果没有实参需要传可以不写调用时的小括号

5、构造函数的函数名首字母大写普通函数我们使用小驼峰方式命名

特殊需求属性

现在我们创建的对象我们都叫基础对象现在我们对对象有一些高级的需求比如有一些特殊属性年龄应该时随着时间的增长而增长的类似这样的属性我们怎么定义

Object.defineProperty() 定义对象属性
var stu1 = {};
Object.defineProperty(stu1,"name",{
	//关于特殊属性的定义
})

现在我们在对象stu1当中定义了个name属性现在它还是一个普通属性现在我们来看下我们可以设置属性的哪些行为描述

数据属性

数据属性就是包含一个数据的位置我们可以在这个位置写入或者读取值有4个描述具体行为的特征

Configurable表示是否可以同delete关键字删除这个属性从而新定义这个属性或者是否能把这个属性修改成访问器属性它的默认值是true

EnumeErable 表示能否被for…in循环遍历返回属性名这个默认值是true

**Writable**表示是否允许修改属性的值默认值是true

value 包含了这个属性的数据值读取属性的时候从这个位置读/写属性值的时候把新信保持在这个位置上默认值是undefined

var stu = {
    aaa:"hello"
}
//我们开始添加一个具备特殊行为描述的数据属性
Object.defineProperty(stu,"name",{
    configurable:false,  //false代表不能被delete删除
    enumerable:false,    //表示不能被for...in循环遍历到
    writable:false,      //不能修改这个值
    value:"小芳"
})

for(var i in stu){
    console.log(i);
}

代码分析

现在我们给stu对象添加了一个name属性对这个属性的各种行为都设置为false表示这个属性即不能被删除也不能被修改还不能被遍历到像一些关键参数我们可以就需要做这样的行为描述避免被误会修改

访问器属性

访问器属性是不能直接被定义的必须使用 Object.defineProperty() 来定义

Configurable表示是否可以同delete关键字删除这个属性从而新定义这个属性或者是否能把这个属性修改成访问器属性它的默认值是true

EnumeErable 表示能否被for…in循环遍历返回属性名这个默认值是true

**Get**在读取属性的时候调用的函数默认值是undefined

Set 在写入属性的时候调用的函数默认值是undefined

var stu = {
    birthday:"1997-7-5"
}
//现在有一个学生对象我们在这个对象里面添加了一个数据属性birthday生日
//现在我们希望再添加一个age属性但是这个age属性的值要根据生日来计算
Object.defineProperty(stu,"age",{
    configurable:false,
    enumerable:true,
    get:function(){
        return "你正在读取age属性"  //访问器属性所调用出来的值由get的return决定
    },
    set:function(v){
        //v表示你赋的值
        console.log("你正在对这个age属性赋值你要赋的值是" + v)
    }
})

上面的get和set定的age属性就是一个访问器属性它在取值和赋值的时候会分别除法get和set方法

接着我们看访问器属性的具体作用

var stu = {
    birthday:"1997-7-5"
}
//现在有一个学生对象我们在这个对象里面添加了一个数据属性birthday生日
//现在我们希望再添加一个age属性但是这个age属性的值要根据生日来计算
Object.defineProperty(stu,"age",{
    configurable:false,
    enumerable:true,
    get:function(){
        var currentDate = new Date();  //获取当前时间点的日期对象
        var birthdayDate = new Date(this.birthday);  //获取出生日期的日期对象
        var totalTime = currentDate.getTime() - birthdayDate.getTime();
        var yearCount = parseInt(totalTime / 1000 / 60 / 60 / 24 / 365);
        return yearCount;
    }
    // set:function(v){
    // 	//v表示你赋的值
    // 	console.log("你正在对这个age属性赋值你要赋的值是" + v)
    // }
})

代码分析

我们给stu对象添加了一个访问器属性age并对age调用时的行为进行了描述对age属性的调用执行了一个get方法

也就是说针对访问器属性的调用和赋值操作

调用执行访问器属性中行为描述的get方法

赋值执行访问器属性中行为描述的set方法

扩展

这里我们使用到了日期对象JS为我们提供了一个Date构造函数通过new调用可以直接获取当前日期的日期对象

同时这里我们在new日期对象的时候我们还使用了传参当new日期对象的时候传入的参数必须是固定的格式 YYYY-MM-DD的字符串

通过上面的访问器属性我们设置了age现在我们还想设置一个sex性别根据身份证号来获取的现在我们需要在stu对象上面添加两个带有特殊行为描述的属性但是 Object.defineProperty 方法一次只能添加一个

Object.defineProperties() 定义对象属性

这个方法其实就是defineProperty的复数形式可以一次定义多个带特殊行为描述的属性

var stu = {
    birthday:"1997-7-5",
    idCard:"420502199707050116"
}			
Object.defineProperties(stu,{
    name:{
        value:"张三",
        configurable:false,
        writable:false
    },
    age:{
        get:function(){
            var currentDate = new Date();  //获取当前时间点的日期对象
            var birthdayDate = new Date(this.birthday);  //获取出生日期的日期对象
            var totalTime = currentDate.getTime() - birthdayDate.getTime();
            var yearCount = parseInt(totalTime / 1000 / 60 / 60 / 24 / 365);
            return yearCount;
        }
    },
    sex:{
        get:function(){
            // if(this.idCard[16] % 2 == 0){
            // 	return "女"
            // }else{
            // 	return "男"
            // }
            return this.idCard[16] % 2 == 0 ? "女" : "男"
        }
    }
})

获取对象属性的描述信息

var nameDesc = Object.getOwnPropertyDescriptor(stu,"name");  //获取name属性的行为描述信息

构造函数与特殊属性结合

构造函数与特殊属性结合主要指的就是构造函数与 Object.defineProperties 的结合这样我们就可以在构造函数的体内直接定义特殊属性通过这个构造函数new出来的对象对象的实例化的属性就一直是一个经过特殊定义的属性

案例

现在我们定义一个Person构造函数这个构造函数实例化的对象有5个属性分别是name,birthday,sex,age,IDCard这5个属性不能被delete同时都是只读age属性根据生日计算sex属性根据身份证号决定

function Person(_name,_birthday,_IDCard){
    Object.defineProperties(this,{
        name:{
            value:_name,
            configurable:false,
            writable:false
        },
        birthday:{
            value:_birthday,
            configurable:false,
            writable:false
        },
        IDCard:{
            value:_IDCard,
            configurable:false,
            writable:false
        },
        age:{
            configurable:false,
            get:function(){
                var currentDate = new Date();
                var birthdayDate = new Date(this.birthday);							
                var totalTime = currentDate.getTime() - birthdayDate.getTime();
                var yearCount = parseInt(totalTime / 1000 / 60 / 60 / 24 / 365);
                return yearCount;
            }
        },
        sex:{
            configurable:false,
            get:function(){
                return this.IDCard[16] % 2 == 0 ? "女" : "男"
            }
        }					
    })
}

var p1 = new Person("张三","2000-1-1","420502200001010222")

对象的继承

通过原型来实现继承

现在我们通过在控制台打印一个new出的来对象在对象中找到一个属性 __proto__ 这个是对象的特殊属性它指向的是对象的原型我们可以对对象的原型理解成对象的父级那么我们就通过这点来实现继承

有一点先说明

在JavaScript的面向对象当中有这么一句话一个对象的__proto__ 应该等于这个对象的构造函数的prototype

p1.__proto__ === Person.prototype   //true

__proto__ 可以设置对象的父级那么 prototype 应该也可以设置对象的父级所以根据这个特点我们额来尝试去完成对象的继承

function Person(_height){
    this.height = _height;
    this.sayHello = function(){
        console.log("大家号我叫haha");
    }
}			
function Student(_userName,_sex,_age,_height){
    this.userName = _userName;
    this.age = _age;
    this.sex = _sex;
    this.__proto__ = new Person(_height) //s1.__proto__ = p1
}
var s1 = new Student("张三","男",18,190)  

this关键字

this 是一个关键字也是一个指针具体指的什么就要看这个关键字谁在调用它

对象中的this
var name = "张三";
var stu = {
    name:"李四";
    sayHello:function(){
        console.log(this.name);
    }
}

上面的代码中我们看到sayHello方法里面有个this那么这个this指向谁

我们之前说过this指向当前调用它的对象

问题这个当前对象到底是谁

1、在全局环境下this指向的当前对象是window

2、在自己定义的对象中this指向当前调用这个方法的对象

根据上面的特点全局环境的this指向window对象那么我们补充以下几点

之前我们在声明变量的时候通过var关键字声明的变量其实还可以理解成是给window对象添加属性通过function关键字声明的函数其实就是给window对象添加方法而直接添加在window对象下的属性和方法在调用的时候是可以不写window对象自己的

var name = "张三";

上面的代码定义了个全局变量其实全局变量就是window对象的属性

window.name = "张三"

因为this在全局环境下指向的是window对象

var name = "张三";
var stu = {
    name:"李四",
    sayHello:function(){
        console.log(this.name);
    }
}
stu.sayHello();

var s = stu.sayHello;
s();

代码分析

var s = stu.sayHello 相当于 window.s = stu.sayHello 所以接下来调用 s() 其实就相当于window.s()

根据我们之前讲过的对象方法里面的this指向调用这个方法的对象现在这个方法被window调用的所以里面的this指向window

构造函数里面的this

函数就是方法在面向对象的思维里面函数就是方法

我们在使用构造函数的时候也使用了this它指向谁

var name = "haha";
function Person(){
	console.log(this.name);
}

构造函数与普通函数在本质上是没有区别的关键在于其调用方式用new调用的函数我们就叫构造函数

Person()    //window.Person(),所以这里的this指向window

new Person()  //构造函数在调用的时候体内的this指向的是当前实例化的对象

函数的不同调用形式决定了this指向

先简单回顾下函数的调用形式

1、方法名()

2、var 方法名 = function(){ }()

3、!function(){ }()

4、(function(){ })()

5、new function(){}

除了上面三种之外我们还有另外的三种调用形式这三种方式也可以改变this指向

通过call方法调用
var name = "张三";
function sayHello(str){
    console.log(str);
    console.log(this.name)
}

var stu1 = {
    name:"李四"
}
var stu2 = {
    name:"王五"
}

sayHello("普通调用");
sayHello.call(window,"我是通过call来调用的");
sayHello.call(stu1,"我是通过call来调用的");
sayHello.call(stu2,"我是通过call来调用的");
通过apply来调用

这个调用方式跟call调用一模一样唯一不同的就是在原来方法的参数赋值上面

var name = "张三";
function sayHello(str,x,y,z){
    console.log(str);
    console.log(x)
    console.log(this.name)
}

var stu1 = {
    name:"李四"
}
var stu2 = {
    name:"王五"
}
sayHello.apply(stu1,["我是通过apply调用的",1,2,3])
通过bind来调用

bind方法在调用方法的时候不会立即执行原来的方法而是返回一个新的方法通过新的方法调用原方法

var name = "张三";
function abc(){
    console.log(this.name);
}
var stu = {
    name:"李四"
}
var x = abc.bind(stu);
x();

如果带有参数

var name = "张三";
function abc(x,y){
    console.log(arguments);
    console.log(this.name,x,y);
}
var stu = {
    name:"李四"
}
var a = abc.bind(stu,99,100);
a();

var b = abc.bind(stu,200);
b()

var c = abc.bind(stu);
c(500,501)

var d = abc.bind(stu,600,601);
d(602,603)

★★★DOM

document object model 文档对象模型主要目的就是把网页里面的元素标签+内容当成一个JS对象来操作

DOM技术的本质就是操作我们二点html元素进行各种各样的操作

DOM技术可以理解成两个部分操作HTML操作CSS

在学习之前我们先简单说明一下

1、document是文档的意思这个文档指向的就是当前网页

2、页面上所有的元素都被js转换到JS里面的对象中去

3、如果是非IE浏览器我们一般会根据一个id来生成一个对象方便我们直接获取

通过JS获取页面元素

1、通过id来获取元素

var user = document.getElementById("user");

通过这种方式获取元素永远只能获取1个或者0个null

2、通过class获取元素

document.getElementsByClassName("类名")

这个方法会返回一个叫做HTMLCollection的集合类数组这个集合里面存放的是DOM对象如果没有获取到返回一个空数组

3、通过标签名获取元素

document.getElementsByTagName("标签名");

这个方法会返回一个叫做HTMLCollection的集合类数组这个集合里面存放的是DOM对象如果没有获取到返回一个空数组

4、通过name属性来获取

document.getElementsByName("name属性值");

这个方法返回的是一个叫做NodeList的集合它也是个类数组

image-20230928101426943

以上4种方式是我们最基础的4种获取元素的方式这些方法兼容性好在绝大部份浏览器都是可以使用的

<div id="div1">
    <div class="div2">我爱北京天安门</div>
    <div class="div2">天安门上太阳升</div>
    <div class="div3">啊哈哈哈</div>
</div>
<div class="div2">我是外面的第二个盒子</div>
<div class="div2">我是外面的第二个盒子的副本</div>
<p>我是一个段落</p>
<script>
    //我要获取id为div1里面的两个类名为div2的元素
    var divList = document.getElementById("div1").getElementsByClassName("div2");
    console.log(divList);
</script>

但是这是很早的解决方案现在我们已经可以不是使用转而另寻新欢强烈推荐

新的方法主要是结合HTML5和CSS3的东西我们直接把CSS种的选择器与JS做了结合

1、通过 querySelector("CSS选择器") 来获取元素

var div1 = document.querySelector("#div1");
var div2 = document.querySelector(".div2");

这种方法通过CSS选择器来获取元素如果选中了就返回一个元素找不到返回null如果找到多个值返回第一个

2、通过 querySelectorAll("CSS选择器") 来获取元素

var div2List = document.querySelectorAll("#div1>.div2")

通过这种方式返回的是一个NodeList集合是一个类数组

总结

get系列的方法相当于是把不同的选择器分成了对应的方法来执行

querySelector 把所有的CSS选择器综合进行使用

DOM结构

DOM本身也是一个对象而我们以前讲过对象都有自己的属性和方法这些属性和方法基本上都是从原型继承来的所以我们看结果可以理解成看对象的原型

分析DOM对象

标签名第一级第二级第三级第四级第五级
divHTMLDivElementHTMLElementElementNodeEventTarget
pHTMLParagraphElementHTMLElementElementNodeEventTarget

通过上面两个标签对象的对比我们可以看到所有的元素都继承自Node对象EventTarget暂时不管我可以把Node当成所有页面元素对象的父级这个时候我们弄清楚Node对象也就弄清除了DOM对象

Element与Node区别

<div id="div1">
    我是前面插入的一段文字
    <div class="div2">我爱北京天安门</div>
    <div class="div2">天安门上太阳升</div>
    <div class="div3">啊哈哈哈</div>
    <!-- 我是一个注释 -->
</div>

1、网页当中的所有标签都可以是一个元素Element,同时也可以是一个节点Node

2、但是并不是所有的节点Node都是一个元素Element节点是可以包含元素、文字、注释、回车…

3、上面网页结构中元素就4个但是节点就很多了

Element常用属性与方法

1、children属性获取当前元素下所有的子元素返回一个HTMLCollection的集合

2、parentElement 属性 获取当前元素的父元素

3、nextElementSibling 当前元素的下一个兄弟

4、previousElementSibling 当前元素的上一个兄弟

以上4个属性以当前元素为中心获取父级、子集、兄弟

5、className属性 获取或者设置当前元素的class属性类名

<div id="div1">
    <div class="div2">2222</div>
    <div class="div2">1111</div>
    <div class="div3 size">啊哈哈哈</div>
</div>
<div class="div2">我是外面的第二个盒子</div>
<div class="div2">我是外面的第二个盒子的副本</div>
<p>我是一个段落</p>
<button onclick="changeColor()">按钮</button>
<script>
    var div3 = document.querySelector(".div3");
    function changeColor(){
        div3.className = "color"
    }

</script>

className有个情况要注意下

虽然上面我们可以通过className的方式操作元素样式了但是实际工作中我们实际不会这么干因为有问题className的赋值是将整个class属性中的值全部替换掉如果出现了一个标签多个类名的情况它会把所有的类名全部替换掉

6、classList属性返回当前元素的class类名的集合它会返回一个叫做DOMTokenList对象类数组在这个集合里面包含了当前元素的所有类名

  • add() 方法在当前元素的classList里面添加一个class
  • remove() 在当前元素的classList中删除一个类名
  • toggle() 如果classList当中有这个类名就删除没有就添加
  • contains() 判断当前元素中是否有这个类名返回布尔

7、firstElementChild 属性获取当前元素下的第一个子元素相当于children[0]

8、lastElementChild 属性 获取当前元素下的最后一个子元素

9、innerText属性 获取或设置当前元素的文本内容 如果赋值的时候是html标签那么依然会按照文本的形式输出不会转义成html标签

10、innerHTML属性获取或设置当前元素的HTML内容如果赋值的时候是html标签会对html标签转义

11、tagName属性获取当前元素的标签名

12、value属性它是表单的专属属性可以调用和赋值

13、childElementCount 属性 获取当前元素的子元素的个数

Element常用方法

1、createElement() 根据标签名创建一个元素

var div1 = document.createElement("div");

2、appendChild() 向当前元素里面的最后去追加一个新的元素

var div1 = document.createElement("div");
div1.innerText = "今天天气不错"
div1.classList.add("color");
var box = document.querySelector(".box");
box.appendChild(div1);

3、remove() 删除当前元素并且子元素会一并删除

var p1 = document.querySelector("p");
p1.remove();

4、removeChild() 删除指定的子元素返回删除掉的子元素

var IDdiv = document.querySelector("#div1");
IDdiv.removeChild(IDdiv.children[1]);

ODdiv.children[1].remove();

5、cloneNode() 克隆一个相同的元素出来这个方法可以接收一个参数默认是false传入一个true表示要连同子元素一起复制

var cloneDiv = IDdiv.cloneNode(true);
var cloneDiv = IDdiv.cloneNode();

6、insertAdjacentElement() 在指定的位置插入元素指定的位置由传入的参数决定

参数值解释
beforeBegin开始标签之前
afterBegin开始标签之后
beforeEnd结束标签之前
afterEnd结束标签之后
IDdiv.insertAdjacentElement("beforeBegin",cloneDiv);

出来以上这个方法可以插入元素还有其他类似的方法

insertAdjacentHTML() 插入网页标签

insertAdjacentText插入文本

var text = "<h2>我是h2标题</h2>"
IDdiv.insertAdjacentHTML("beforeBegin",text)   //innerHTML类似
IDdiv.insertAdjacentText("beforeBegin",text)   //innerText类似

Event事件:

事件是DOM对象里面一个特殊属性它需要经过一个条件触发与普通属性相比最大的区别就是属性值事件作为一个特殊属性它接收的值是一个function 或者直接写一个执行语句也行

<button type="button" id="btn" onclick="sayHello()">按钮</button>
<button type="button" onclick="console.log('hello')">再来点我</button>	
<script type="text/javascript">
    function sayHello(){
        console.log("hello");
    }
</script>

用户触发了事件事件调用了方法

按照W3C的标准DOM事件被分为了两个级别

0级DOM事件

这是一个基本的DOM事件0级事件本质上就是一个DOM对象的属性只是这个属性比较特殊

1、属性值都是一个function

2、这些属性都是以on开头

在0级书简中我们的事件又可以分为以下几个类

1、鼠标事件

2、键盘事件

3、文档事件

4、其他事件

事件绑定

第一种绑定方式

<button type="button" onclick="console.log('hello')">再来点我</button>	

第二种绑定方式

<button type="button" id="btn" onclick="sayHello()">按钮</button>
<script type="text/javascript">
    function sayHello(){
        console.log("hello");
    }
</script>

第三种绑定方式具名函数

var btn = document.querySelector("#btn1");			
function sayHello(){
    console.log("hello");
}
btn.onclick = sayHello;

第三种绑定方式匿名函数

var btn = document.querySelector("#btn1");	
btn.onclick = function(){
    console.log("hello");
};

现在我们有个问题我们现在有个无序列表我现在想给每一个列表项绑定一个点击事件当点击当前li的时候改变当前文字颜色怎么实现

<ul>
    <li>1</li> 
    <li>2</li>	
    <li>3</li>
    <li>4</li>
    <li>5</li>
</ul>
<script>
    var liList = document.querySelectorAll("li");
    for(var i = 0;i < liList.length;i++){
        liList[i].onclick = function(){
            this.classList.toggle("active");
        }
    }
</script>

0级事件的批量绑定的注意事项

场景现在页面上有10个按钮我们希望对这10个按钮绑定一个onclick事件每个按钮点击的时候在控制台打印当前按钮的序号怎么实现

<button type="button">0</button>
<button type="button">1</button>
<button type="button">2</button>
<button type="button">3</button>
<button type="button">4</button>
<button type="button">5</button>
<button type="button">6</button>
<button type="button">7</button>
<button type="button">8</button>
<button type="button">9</button>
<script>
    var btnList = document.querySelectorAll("button");
    for(var i = 0;i < btnList.length;i++){
        btnList[i].onclick = function(){
            console.log(btnList[i].innerText);
        }
    }
</script>

代码分析

以上的写法是错误的因为for循环已经执行完毕i的值已经固定成了10这个时候当我们去触发事件事件再调用方法的时候方法里面的 i 调用的值就是10了所以实际当你触发执行方法的时候调用的是 btnList[10] 但是集合里面没有索引为10的这个元素所以报错

解决方案一通过this

var btnList = document.querySelectorAll("button");
for(var i = 0;i < btnList.length;i++){
    btnList[i].onclick = function(){
        console.log(this.innerText);
    }
}

这种方式用户触发了事件事件再调用方法所以事件方法里面的this指向当前DOM对象

解决方案二通过闭包立即执行

var btnList = document.querySelectorAll("button");
for(var i = 0;i < btnList.length;i++){
    btnList[i].onclick = (function(j){
        return function(){
            console.log(btnList[j].innerText);
        }
    })(i)
}

事件对象event重点

事件对象是所有事件都具备的当用户触发事件的时候事件会调用方法事件再调用方法的过程种会向当前方法注入一个参数这个参数就是一个事件对象event

获取事件对象
<div class="box">事件对象</div>
<script>
    var box = document.querySelector(".box");
    box.onclick = function(e){
        e = event || window.event;  //兼容写法保障我们在不同的浏览器种都可以正确调用到事件对象
        console.log(e);
    }
</script>

事件传播

简单解释一个DOM对象上面的事件会传播给另外一个DOM对象

<div class="box">
    <button id="btn">按钮</button>
</div>
<script>
    var box = document.querySelector(".box");
    var btn = document.querySelector("#btn");
    box.onclick = function(){
        console.log("我是box")
    }
    btn.onclick = function(){
        console.log("我是btn")
    }
</script>

代码分析

上面的代码种我们点击box中的btn按钮的时候我们发现两个事件都被触发了这就说明一点内部按钮的onclick事件的行为传递给了外面元素box的onclick上面这种现象我们叫做事件冒泡

事件冒泡

事件冒泡就指事件由内向外传播

取消事件冒泡
e.cancelBubble = true;   //取消事件冒泡
e.stopPropagation();     //取消事件传播
事件的触发者与绑定者
<div class="box">
    <button id="btn">按钮</button>
</div>
<script>
    var box = document.querySelector(".box");
    var btn = document.querySelector("#btn");
    box.onclick = function(e){
        e = event || window.event;
        console.log("我是box");
        console.log("target",e.target);
        console.log("currentTarget",e.currentTarget);
    }
</script>

代码分析

上面的按钮点击了btn但是这个按钮本身是没有绑定事件所以就算点击了这个按钮也不会有任何的触发但是它会冒泡到外面的box上面外面box是绑定的有事件的导致btn的点击行为传播到了外面的box上面因此触发了box身上的事件那么box的的事件实际上是由btn触发的

这里我们理解btn是触发box是绑定

target是事件的触发者

currentTarget是事件的绑定者

事件冒泡实现事件委托
<button onclick="addNewLi()">添加列表项</button>
<ul class="ul1">
    <li>1</li>
    <li>2</li>
    <li>3</li>
    <li>4</li>			
</ul>
<script>
    function bindEvent(){
        var liList = document.querySelectorAll(".ul1>li");
        for(var i = 0; i < liList.length;i++){
            liList[i].onclick = function(){
                console.log(this.innerText)
            }
        }
    }
    bindEvent();

    //当点击一个按钮的时候向列表中新增列表项
    function addNewLi(){
        var newLi = document.createElement("li"); //创建一个li元素
        newLi.innerText = "新增的项";   //给创建好的li设置一个内容
        document.querySelector(".ul1").appendChild(newLi); //获取ul列表向这个列表里面的最后面添加li
        bindEvent();
    }
</script>

代码分析

上面的代码中我们每添加一个新的li都需要重新执行一遍事件绑定这样非常消耗性能我们转换下思考方式能不能把这个事件绑定到li的父级ul上然后让里面的元素通过事件冒泡来执行绑定在父元素上面的事件方法

var ul1 = document.querySelector(".ul1");
ul1.onclick = function(e){
    e = event || window.event;
    console.log(e.target.innerText);
}
function addNewLi(){
    var newLi = document.createElement("li"); //创建一个li元素
    newLi.innerText = "新增的项";   //给创建好的li设置一个内容
    document.querySelector(".ul1").appendChild(newLi); //获取ul列表向这个列表里面的最后面添加li
}

代码分析

上面的代码就是基本的事件委托代码这个过程中onclick事件本来应该绑定在li身上但是现在委托给了ul进行绑定然后利用事件冒泡的原理进行事件的传递传播,传递给了外面的ul这种现象就是事件委托

现在我们想让指定的元素成为触发者只有点击指定的元素才会触发事件完成委托那么现在需要判断触发者为指定元素

在DOM对象里面由一个API方法matches() 来完成判断

var ul1 = document.querySelector(".ul1");
ul1.onclick = function(e){
    e = event || window.event;
    if(e.target.matches("li.active")){
        console.log(e.target.innerText);
    }				
}
function addNewLi(){
    var newLi = document.createElement("li"); //创建一个li元素
    newLi.innerText = "新增的项";   //给创建好的li设置一个内容
    document.querySelector(".ul1").appendChild(newLi); //获取ul列表向这个列表里面的最后面添加li
}

代码分析

这里使用的matches方法通过css选择器来指定元素将指定好的元素的css选择器作为参数传入来指定触发者

元素的默认行为

有些标签在经过JS的处理之后还由有一些响应比如a标签

<a href="https://www.baidu.com">百度一下</a>
<script>
    var a1 = document.querySelector("a");
    a1.onclick = function(){
        alert("hello world")
    }
</script>

在上面的代码中当我们点击a标签的时候它会执行onclick事件然后在去执行a标签的跳转

我们可以在事件当中取消这个某些元素的默认行为只需要在事件方法的后面返回一个false即可

a1.onclick = function(){
    alert("hello world");
    return false;
}

同样的其他自带默认行为的html标签页是同理比如重置按钮之类的

2级事件

在2级事件中所有的事件都通过一个监听的方法来绑定

添加监听
DOM对象.addEventListener("事件名",function(){},传播方向)

举例

var btn = document.querySelector("button");
function sayHello(){
    console.log("hello");
}
btn.addEventListener("click",sayHello)

也可以直接传入要给匿名回调函数

var btn = document.querySelector("button");
btn.addEventListener("click",function(){
    console.log("ahhahaha")
})

2级事件与0级事件的区别点

1、0级事件都是以属性存在的2级事件都是以事件监听的形式存在的

因为0级事件是以属性存在的所以每次赋值新的方法会把老方法覆盖掉而2级事件可以实现多次监听

var btn = document.querySelector("button");
btn.addEventListener("click",function(){
    console.log("ahhahaha")
})
btn.addEventListener("click",function(){
    console.log("呵呵呵呵")
})

2、0级事件都是以on开头2级事件在监听的时候都是去掉了on

3、0级事件不可以改变事件传播的方法2级事件可以

移除2级事件监听

移除在2级事件当中专门提供了一个方法 removeEventListener 来完成

var box = document.querySelector(".box");
var btn = document.querySelector("button");
function a(){
    console.log("我是box")
}
box.addEventListener("click",a);
btn.addEventListener("click",function(){
    box.removeEventListener("click",a);
})

如果我们希望某一个事件的方法只被执行一次怎么办

var btn = document.querySelector("#btn");
btn.addEventListener("click",function(e){
        console.log("我是一次性按钮");
        console.log(arguments);
        e = event || window.event;
        this.removeEventListener(e.type,arguments.callee);
    }
)

代码分析

e.type 指当前事件的类型名称click

arguments.callee 指向当前函数的引用也就是函数本身

2级事件取消默认行为

<a href="http://www.baidu.com">百度一下</a>
<script>
    var a1 = document.querySelector("a");
    a1.addEventListener("click",function(e){
        e = event || window.event;
        alert("我是2级事件");
        e.preventDefault();  //阻止默认行为return false在2级事件中没用
    })
</script>

我们打印出事件对象

image-20230925101111342

正则表达式

正则表达式并不是JS独有的技术基本上所有语言都支持这个技术

正则表达式的目的也很单纯核心作用就是验证数据的合法性

正则表达式的特点

1、正则表达式在JS中只针对字符串起作用

2、正则表达式会根据你设置的规则对字符串进行 提取搜索、替换 等操作

3、JavaScript中正则表达式是一个内置对象这个对象通过RegExp() 创建也可以直接通过赋值一个正则表达式来创建

第一种

var reg = new RegExp(正则表达式)

第二种:

var reg = //

方法

1、test() 用于验证某一个字符串是否符合正则的规则

var str ="abc";
var reg = /a/;
reg.test(str);

2、exec根据正则表达式提取字符串中符合要求的字符用法与上面类似注意正则表达式是可以添加修饰符的这个修饰符会影响提取字符串的结果

修饰符

1、g代表global全局验证

2、i 代表忽略大小写

3、m 代表多行的意思也就是可以换行匹配

正则表达式的规则

一元符号

. 匹配除换行符以外的任意符号

\w 匹配字符数字和下划线

\S匹配任何空白符

\d 匹配所有数字 ,与 [0-9]

\b 匹配单词边界

| 或匹配

^ 匹配字符串的开始

$ 匹配字符串的结束

原子组和原子表

原子表
var reg = /^[张王赵]三$/
console.log(reg.test("张三"));
console.log(reg.test("王三"));
console.log(reg.test("赵三"));
console.log(reg.test("李三"));
console.log(reg.test("张四"));
console.log(reg.test("张三ssss"));
console.log(reg.test("张ssss三"));

原子表是用中括号的形式存在它会从这个表中拿出一个进行条件匹配

在原子表中还可以写范围

var reg1 = /[0-9]/
var reg2 = /[a-z]/
var reg3 = /[A-Z]/

注意原子表中的范围不能倒写会报错

原子组
var reg = /张三|王三|赵三/;
var reg2 = /(张|王|赵)三/    //原子组用小括号表示

反义字符

[^x] 匹配处理x以外的所有字符这里的x可以是任意字符

[^xyz] 同上匹配除了xyz以外的字符

\W 匹配除字母、数字、下划线以外的所有字符等同 [^\w]

\B 匹配不是单词边界的字符

转义字符

\xnn 匹配十六进制数

\f 匹配换页符

\n 匹配换行符

\r 匹配回车符

\unnnn 匹配unicode编码

重复匹配

* 重复匹配零次或多次

+ 重复匹配1次或多次

? 重复匹配0次或1次

{n} 重复匹配n次

{n,} 至少重复匹配n次

{m,n} 重复普配m到n次 m < n

//我希望验证一个字符串它是a开始c结束中间有4个英文字母。怎么写
var reg = /^a[a-zA-Z]{4}c$/

//我希望验证一个字符串它是a开始c结束中间有4-6个数字。怎么写
var reg1 = /^a\d{4,6}c$/

//我希望验证一个字符串它是a开始c结束中间至少有4个数字。怎么写
var reg2 = /^a\d{4,}c$/

//我希望验证一个字符串它是a开始c结束中间至少有1个或多个数字。怎么写
var reg3 = /^a\d+c$/

//我希望验证一个字符串它是a开始c结束中间至少有0个或多个数字。怎么写
var reg4 = /^a\d*c$/

//我希望验证一个字符串它以三结束以张开头中间有0或1个字符
var reg5 = /^张.?三$/

贪婪与惰性

重复匹配默认都是按照贪婪的特性去匹配较多的次数如果我们需要按照惰性特征来匹配

我们可以把上面的多有的重复匹配符号后面加上一个 表示惰性匹配

var str = "cawqdewfeffwerderwe";
//我要提取c开始到d结束中间任意长度的字符串
var reg = /c[a-z]*d/;
var newStr = reg.exec(str);
//这个时候我们的正则表达式处在贪婪模式下它会执行贪婪0到贪婪多次

var reg = /c[a-z]*?d/;  //执行惰性重复匹配

原子组编号

原子组通过形成一个分组这个分组会给一个分组编号

var str = "<div></div>";
//现在希望通过正则验证这个标签
var reg = /<[a-zA-Z]+><\/[a-zA-Z]+>/;
//上面的问题在于我们希望开始标签和结束标签里面匹配到的是相同的字符
var flag = reg.test(str);

在上面的表达式中我们表面上看起来是完成了功能但是又有隐患如果我们要匹配的字符串是 <div></span> 这样也会验证成功但是不符合要求

我们的主要需求是开始标签和结束标签要一致我们开始匹配的内容 <[a-zA-Z]+> 要与后面匹配的 <\/[a-zA-Z]+> 保持一致这个时候我们就要用到原子组

var str = "<div></span>";
//现在希望通过正则验证这个标签
var reg1 = /<[a-zA-Z]+><\/[a-zA-Z]+>/;
//上面的问题在于我们希望开始标签和结束标签里面匹配到的是相同的字符
var flag1 = reg1.test(str);

var reg2 = /<([a-zA-Z]+)><\/\1>/;
var flag2 = reg2.test(str);

前瞻后顾

首先我们要弄清除两个条件

1、你的匹配条件是什么

2、你的限制条件是什么

前瞻

匹配条件是A限制条件是BB要出现在A的后面

A(?=B)

如果要匹配abc并且abc要在123的前面

/abc(?=123)/g

//abc123  true
//abc456  false
//123abc  false
负前瞻

匹配条件是A限制条件是BB不能出现在A的后面

/abc(?!123)/g
后顾

匹配条件是A限制条件是BB要出现在A的前面

(?<=B)A

要匹配abc并且abc要在123的后面

/(?<=123)abc/g

//abc123  false
//abc456  false
//123abc  true
负后顾

匹配条件是A限制条件是BB要不能出现在A的前面

(?<!B)A

特殊情况

如何匹配中文

var reg = /^[\u4E00-\u9FA5]{2,4}$/

BOM

BOM全称broswer object model 浏览器对象它主要是为我们提供了浏览器向外暴露的API我们可以通过这些浏览器向外暴露的API来操作浏览器

location

location的值就是浏览器的地址栏

1、hostname 代表网页的主机名

2、port 代表当前网页的端口

3、host 代表当前网页的主机地址包含了hostname和port

4、protocol 网页传输协议 比如http/ https

5、pathname 代表当前网页域名后面的 / 以后的部分

6、origin 代表当前网页的域信息它由协议名、主机名、端口号共同组成

7、hash 代表当前网页的地址中 # 后面的部分

重点这是一个非常重要的东西后面的SPA单页面开发必不可少

8、search 当前地址栏中 后面的所有东西

超级重点超级重要的东西后面不管是MVC还是MVVM开发模式都需要使用它它主要实现的是页面间传值客户端与服务端传值

9、href 当前浏览器地址栏中的地址它是可以取值也可以赋值的如果赋值页面跳转

10、assign() 载入一个新地址用法和href把地址作为参数传入

11、replace() 替换地址栏的地址网页会实现跳转

12、reload 代表刷新

history

这个对象用于访问当前浏览器的历史记录

1、length 当前历史记录有几条

2、back() 在历史记录中后退一步

3、forward() 在历史记录中向前一步

4、go(step) 如果step是正值向前操作负值向后操作

window

window是我们的浏览器也就是全局对象

1、alert()

2、confirm() 弹出一个询问框点击确定按钮返回true点击取消按钮返回false

3、prompt() 弹出一个内容输入框点击确定返回输入的内容点击取消返回null

4、open() 打开一个新网页新的网页称为子页面可以传入三个参数

参数1要打开的网址

参数2用什么方式打开 相当于a标签的target属性写的实参也是target的值

参数3打开新窗口的行为样式

父子页面

open方法在使用的十四号会打开一个新页面比如a.html通过open打开b.html 那么b现在就是a的子页面

<h2>我是a页面</h2>
<button onclick="openNewPage()">我是父页面按钮</button>
<button onclick="changeChild()">修改子页面</button>
<script>
    var childWindow;
    function openNewPage(){
        childWindow = open("b.html","_blank");
    }
    function changeChild(){
        childWindow.document.querySelector("h2").innerText = "我是你爸爸派来的"
    }
</script>

通过open方法打开的页面中我们可以在子页面的window对象中调出一个opener属性这个属性里面装的是父页面的window对象

<h2>我是b页面</h2>
<button onclick="changeFather()">修改父页面</button>
<script>
    function changeFather(){
        var parentWindow = window.opener;
        parentWindow.document.querySelector("h2").innerText = "我是你儿子"
    }
</script>

localStorage本地缓存重点

image-20230928102120415

localStorage它可以将字符串数据储存在本地浏览器中它是window对象下的一个属性对象

1、setItem(key,value) 设置一个缓存

2、getItem(key) 获取一个缓存

3、removeItemkey 删除一个缓存

4、clear() 清除所有缓存

localStorage.setItem("userName","张三");
var str = localStorage.getItem("userName");
console.log(str);

localStorage.setItem("age",18);
var age = localStorage.getItem("age");
console.log(age);

localStorage.removeItem("age");

localStorage.clear();

缓存是以一个对象的形式存在的所以我们可以像操作字面量对象一样设置缓存

localStorage.userName = "张三";
localStorage.age = 18;
console.log(localStorage.age);
delete localStorage.userName;
关于本地缓存的特点

1、你不主动删除它会一直在

2、可以跨页面访问后面我们可以通过这种方式实现跨页面传值

3、不可以跨域访问

4、不可以跨浏览器访问

session会话缓存

先理解什么是会话浏览器域服务器之间的链接

所谓的会话就是指浏览器到服务器之间的一个来回过程但是总会有聊崩的时候也就是浏览器与服务器之间断开链接的时候而一旦断开储存在session中的缓存数据就会销毁

它与localStorage的操作方法是一样的

1、setItem(key,value) 设置一个缓存

2、getItem(key) 获取一个缓存

3、removeItemkey 删除一个缓存

4、clear() 清除所有缓存

session也跟本地缓存一样可以作为一个对象 sessionStorage使用

sessionStorage.age = 18;
delete sessionStorage.age

特点

1、在浏览器关闭的时候会话会自动销毁

2、会话默认是不允许跨页面调用的但是可以通过父子页面

  • 通过window.open() 开打的页面是可以互动的
  • 通过a标签打开的但是target=“_self” 打开的也可以进行互动

3、不能跨域

4、不能跨浏览器

JSON对象重点

先看一个情况

var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}

localStorage.setItem("stu",stu);
var a = localStorage.getItem("stu");
console.log(a);
//这个时候我们会发现缓存不了对象

代码分析

在上面的代码中我们看到我们需要给当前缓存中缓存的数据是一个对象但是缓存的结果却是[object Object] 这样的结果意味着对象不能直接缓存系统会自动把对象转成字符串缓存但是转成了数据类型来进行缓存

这个时候JSONJavaScript Object Notation JS对象简谱这是一个轻量级的数据转换格式

通俗一点讲JSON就是以字符串的形式来表示对象

var obj = {
	userName:"haha",
	age:18
}

//"{'userName':'haha','age':'18'}"
JSON的序列表
var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}
var str = JSON.stringify(stu);
localStorage.setItem("stu",str);
var a = localStorage.getItem("stu");
console.log(a);

这个时候我们将对象转换成JSON字符串这个过程我们就交JSON的序列化通过JSON.stringify() 方法实现

JSON的反序列化
var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}
var str = JSON.stringify(stu);
localStorage.setItem("stu",str);
var a = JSON.parse(localStorage.getItem("stu"));
console.log(a);

URL对象

URL对象和location比较相似但是比location更高级

var str = "http://www.xxxxx.com:8080/abc/1.html?cation=getAllList&age=18#box";
var u = new URL(str);
URLSearchParams对象

在创建号的URL对象中有一个属性叫做searchParams这个属性里面装的是一个叫做URLSearchParams的对象

这个对象可以实现通过地址栏传值

a.html

<input type="text" id="userName">
<input type="password" id="pwd">
<button type="button" onclick="checkLogin()">登录</button>
<script>
    function checkLogin(){
        var userName = document.querySelector("#userName").value;
        var pwd = document.querySelector("#pwd").value;
        window.open("admin.html?userName=" + userName + "&pwd=" + pwd);
        //admin.html?userName=xxxx&pwd=xxxx
    }
</script>

admin.html

<h2></h2>
<script>
    var u = new URL(location.href);
    var a = u.searchParams.get("userName");
    var b = u.searchParams.get("pwd");
    document.querySelector("h2").innerText = "你之前的登录账号" + a + ",你的登录密码是" + b;
</script>

代码分析

在a.html中我们在跳转页面的时候给地址的后面追加了一个search部分这个search不会影响跳转的我们真正实现条件的是地址栏中pathname的部分后面的hash和search部分对跳转没有影响

2、admin.html中我们将location.href的地址转换成了url对象然后通过url对象中的searchParams来操作search后面传递过来的参数

URL编码与转码

当网页地址出现中文的浏览器在操作的时候会自动编码

这个时候我们需要方法将其转回来

var str = encodeURIComponent(location.href + "?abc=急啊急啊");  //把中文转换
var url = decodeURIComponent(str);   //把转码之后结果解码

总结:

以上便是JavaScriptHTMLCSS的知识总结接着会持续更新AjaxjQueryvueReact

```

通过open方法打开的页面中我们可以在子页面的window对象中调出一个opener属性这个属性里面装的是父页面的window对象

<h2>我是b页面</h2>
<button onclick="changeFather()">修改父页面</button>
<script>
    function changeFather(){
        var parentWindow = window.opener;
        parentWindow.document.querySelector("h2").innerText = "我是你儿子"
    }
</script>

localStorage本地缓存重点

[外链图片转存中…(img-BbR3QI52-1695886174185)]

localStorage它可以将字符串数据储存在本地浏览器中它是window对象下的一个属性对象

1、setItem(key,value) 设置一个缓存

2、getItem(key) 获取一个缓存

3、removeItemkey 删除一个缓存

4、clear() 清除所有缓存

localStorage.setItem("userName","张三");
var str = localStorage.getItem("userName");
console.log(str);

localStorage.setItem("age",18);
var age = localStorage.getItem("age");
console.log(age);

localStorage.removeItem("age");

localStorage.clear();

缓存是以一个对象的形式存在的所以我们可以像操作字面量对象一样设置缓存

localStorage.userName = "张三";
localStorage.age = 18;
console.log(localStorage.age);
delete localStorage.userName;
关于本地缓存的特点

1、你不主动删除它会一直在

2、可以跨页面访问后面我们可以通过这种方式实现跨页面传值

3、不可以跨域访问

4、不可以跨浏览器访问

session会话缓存

先理解什么是会话浏览器域服务器之间的链接

所谓的会话就是指浏览器到服务器之间的一个来回过程但是总会有聊崩的时候也就是浏览器与服务器之间断开链接的时候而一旦断开储存在session中的缓存数据就会销毁

它与localStorage的操作方法是一样的

1、setItem(key,value) 设置一个缓存

2、getItem(key) 获取一个缓存

3、removeItemkey 删除一个缓存

4、clear() 清除所有缓存

session也跟本地缓存一样可以作为一个对象 sessionStorage使用

sessionStorage.age = 18;
delete sessionStorage.age

特点

1、在浏览器关闭的时候会话会自动销毁

2、会话默认是不允许跨页面调用的但是可以通过父子页面

  • 通过window.open() 开打的页面是可以互动的
  • 通过a标签打开的但是target=“_self” 打开的也可以进行互动

3、不能跨域

4、不能跨浏览器

JSON对象重点

先看一个情况

var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}

localStorage.setItem("stu",stu);
var a = localStorage.getItem("stu");
console.log(a);
//这个时候我们会发现缓存不了对象

代码分析

在上面的代码中我们看到我们需要给当前缓存中缓存的数据是一个对象但是缓存的结果却是[object Object] 这样的结果意味着对象不能直接缓存系统会自动把对象转成字符串缓存但是转成了数据类型来进行缓存

这个时候JSONJavaScript Object Notation JS对象简谱这是一个轻量级的数据转换格式

通俗一点讲JSON就是以字符串的形式来表示对象

var obj = {
	userName:"haha",
	age:18
}

//"{'userName':'haha','age':'18'}"
JSON的序列表
var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}
var str = JSON.stringify(stu);
localStorage.setItem("stu",str);
var a = localStorage.getItem("stu");
console.log(a);

这个时候我们将对象转换成JSON字符串这个过程我们就交JSON的序列化通过JSON.stringify() 方法实现

JSON的反序列化
var stu = {
    stuName:"张三",
    age:18,
    sex:"男"
}
var str = JSON.stringify(stu);
localStorage.setItem("stu",str);
var a = JSON.parse(localStorage.getItem("stu"));
console.log(a);

URL对象

URL对象和location比较相似但是比location更高级

var str = "http://www.xxxxx.com:8080/abc/1.html?cation=getAllList&age=18#box";
var u = new URL(str);
URLSearchParams对象

在创建号的URL对象中有一个属性叫做searchParams这个属性里面装的是一个叫做URLSearchParams的对象

这个对象可以实现通过地址栏传值

a.html

<input type="text" id="userName">
<input type="password" id="pwd">
<button type="button" onclick="checkLogin()">登录</button>
<script>
    function checkLogin(){
        var userName = document.querySelector("#userName").value;
        var pwd = document.querySelector("#pwd").value;
        window.open("admin.html?userName=" + userName + "&pwd=" + pwd);
        //admin.html?userName=xxxx&pwd=xxxx
    }
</script>

admin.html

<h2></h2>
<script>
    var u = new URL(location.href);
    var a = u.searchParams.get("userName");
    var b = u.searchParams.get("pwd");
    document.querySelector("h2").innerText = "你之前的登录账号" + a + ",你的登录密码是" + b;
</script>

代码分析

在a.html中我们在跳转页面的时候给地址的后面追加了一个search部分这个search不会影响跳转的我们真正实现条件的是地址栏中pathname的部分后面的hash和search部分对跳转没有影响

2、admin.html中我们将location.href的地址转换成了url对象然后通过url对象中的searchParams来操作search后面传递过来的参数

URL编码与转码

当网页地址出现中文的浏览器在操作的时候会自动编码

这个时候我们需要方法将其转回来

var str = encodeURIComponent(location.href + "?abc=急啊急啊");  //把中文转换
var url = decodeURIComponent(str);   //把转码之后结果解码

总结:

以上便是JavaScriptHTMLCSS的知识总结接着会持续更新AjaxjQueryvueReact

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
返回列表

上一篇:wustctf2020

下一篇:Oracle 快速入门