Javascript学习小结(一) | 青训营笔记

125 阅读19分钟

这是我参与「第四届青训营 」笔记创作活动的第2天。

JavaScript

在一个网页中:

  • html表示结构
  • css表示样式
  • js表示行为

JavaScript是什么

  • JavaScript是世界上最流行的语言之一,是一种运行在客户端的==脚本语言==(Script——脚本)
  • 脚本语言:不需要编译,运行过程中由==js解释器(JS引擎)逐行来进行解释并执行
  • 现在也可以基于Node.js技术进行服务器端编程

JS的三大核心

  • ECMAScript:JS的标准,语法
  • BOM(Browser Object Model):一整套操作浏览器的属性和方法
  • DOM(Document Object Model):一整套操作文档流的属性和方法

JS的本质

通过JS的语法让浏览器、文档发生变化

浏览器执行JS

浏览器分成两部分:渲染引擎和JS引擎

  • ==渲染引擎==:用来解析HTML与CSS,俗称内核,比如chrome浏览器的blink(老版本的webkit)
  • ==JS引擎==:也成为JS解释器。用来读取网页中的JavaScript代码,对其处理后运行,比如chrome浏览器的V8

浏览器本身不会执行JS代码,而是通过内置JavaScript引擎(解释器)来执行JS代码。JS引擎执行代码时逐行解释每一句源码(转换为机器语言),然后由计算机去执行。

JavaScript的引入方式

行内引入

  1. a标签 a标签本身有行为出现(跳转浏览器页面),点击时需要区分“跳转”还是“执行JS代码” 若要执行JS代码,可在href属性里写一个“ javascript: JS代码 ”
  2. 非a标签 本身没有行为,需要我们手动给它加一个行为,写一个onclick属性,表示点击时 e.g.

内部引入: 不需要任何行为,打开页面就会执行 特点:一个页面可以写无限个script标签,按照从上到下的顺序依次执行 建议将放在body标签末尾

e.g. 属性 值 描述 type MIME-type(type/subtype) 规定脚本的 MIME 类型 MIME(Multipurpose Internet Mail Extensions)类型:一种标准,用来表示==文档、文件或字节流的性质和格式== 重要: 浏览器通常使用MIME类型(而不是文件扩展名)来确定如何处理URL,因此Web服务器在响应头中添加正确的MIME类型非常重要。如果配置不正确,浏览器可能会曲解文件内容,网站将无法正常工作,并且下载的文件也会被错误处理。 外部引入: 通过script标签的src属性引入页面 不需要任何行为,打开页面就会执行 特点:一个页面可以写无限个script标签,按照从上到下的顺序依次执行; 写了src属性后(使用外部引入),写在script标签对内部的内容没有意义 e.g.

## javaScript注释
```javascript
//单行注释    /*多行注释*/

javaScript输出语句

alert()弹出警示框    console.log()控制台打印输出信息    document.write()直接把内容输出到页面上,可以解析标签(创建元素,如果页面文档流加载完毕,再调用这句话会导致页面重绘)
👉👉👉只要不是纯数字,都用(单)引号包裹
​
promet()弹出输入框,用户可以输入

变量

​
 - 一个变量只能由 数字(0-9),字母(a-z A-Z),美元符($),下划线(_)组成
 - 一个变量不能以 数字 开头
 - JS中严格区分大小写
 - 不能使用关键字或保留字
​
var a=1 声明变量名为a并赋值为1

数据类型

基本/简单数据类型(值类型)————存放在栈里,存放的是值
1.Number 数字型    2.String 字符串   3.Boolean 布尔值
4.underfinded 未定义    5.Null 空值(返回一个空的 对象 )
 
复杂数据类型:(地址/引用数据类型)————存放在堆里,先在栈里存放地址(十六进制),这个地址指向堆里的数据
通过 new 关键字创建的对象(系统对象、自定义对象)
6.Object    7.Array    8.Date等
​
1.包括十进制、浮点数、其它进制(十六进制 0x开头,八进制 0开头,二进制 0b开头)
!:控制台在输出其它进制数的时候会自动转化成 十进制
   科学计数法:men表示m*10^n
   NaN:非数字

判断数据类型

isNaN()用来判断一个变量是否为非数字类型返回true表示不是数字型。

获取数据类型

typeof 语法:console.log(typeof 变量名)

数据类型转换

使用表单prompt获取过来的数据默认是字符串类型的此时就不能直接简单地进行加法运算需要转换变量的数据类型,通俗来说就是把一种数据类型的变量转换成另一种数据类型。
数字型转换为字符串类型
语法(1):变量.toString()
例:var num=10      var str=num.toString()
语法(2):String(变量)
例:var num=10      var str=string(num)
语法(3):和字符串拼接的结果都是字符串(隐式转换)

转换为数字型

语法(1):parseInt(变量) 转换为数字型得到的是整数
语法(2):parseFloat(变量) 转化为数字型得到的是小数浮点数
语法(3):Number(变量) 强制转换为数字型

转换为布尔型

语法:Boolean 其他类型转化为布尔型代表空值,否定的值会被转换为false。
如:0 NaN Null nudefind,其余的值都会转化为true

运算符

(1)算数运算符:+ - * / %
(2)前置自增自减运算符:++num --num (前置先加1后返回值)
(3)后置自增自减运算符num++ num-- (后置返回原值后加1)
(4)比较运算符:< > >= <= = != === !==
(5)逻辑运算符:&&与 ||或 !非
重点:= 赋值,把右边的值给左边
    == 比较,判断两边的值是否相等
    ===全等,判断两边的 值 和 数据类型 是否完全相等

流程控制-if语句

(1)if语句 语法:if(条件表达式){执行语句}
(2)if else语句 语法:if else(条件表达式){条件执行成立的代码}else{条件不成立时执行的代码}
(3)if else if语句 语法:if(){}else if(){}else if(){}else{}

三元表达式

语法:条件表达式?表达式1:表达式2:num>5?"大于":"不大于";
执行思路:如果条件表达式为真,则返回表达式1的值,如果条件表达式的结果为假,则返回表达式2的值。

流程控制-switch语句

语法:switch(表达式value值){case value值:
                         执行语句1;
                         break;
                         default:执行最后的语句}
执行思路:利用表达式的值和case后面的选项值相匹配,如果匹配上就执行该case里面的语句,如果都没有匹配上,那么执行default里面的语句。
switch注意事项:
1.在开发时表达是我们经常写成变量
2.num的值和case里面的值相匹配的时候是全等,必须是和值的数据类型一致
3.break如果当前case里面没有break不会退出switch,是继续执行下一个case

switch和if else if语句区别

1.一般情况下,他们两个语句可以相互替换
2.switch...case语句通常处理case为比较确定值的情况,而if...else语句更加灵活,常用于范围判断(大于等于某个范围)
3.switch语句进行条件判断后直接执行程序的条件语句效率更高。而if...else语句有几种条件就得判断多少次。
4.当分支比较少时,if...else语句执行效率比switch语句高。
5.当分支比较多时,switch语句的执行效率比较高,而且结构更清晰。

循环-for循环

在程序中,一组被重复执行的语句被称为循环体,能否继续重复执行取决于循环的终止条件。由循环体及循环的终止条件组成的语句称之为循环语句。
语法结构:for(初始化变量;条件表达式;操作表达式){循环体}
1.初始化变量就是用var声明的一个普通变量,常用于作为计数器使用。
2.条件表达式就是用来决定每一次循环是否继续执行就是终止的条件。
3.操作表达式是每次循环最后执行的代码,通常我们用于计数器变量进行更新。

循环-while循环

语法结构:while(条件表达式){循环体}

continue关键字

continue关键字用于立即跳出本次循环,继续下一次循环(本次循环中continue之后的代码就会少执行一次)

break关键字

break关键字用于即跳出整个循环(循环结束)

数组

创建数组(1):var 数组名=new Array()利用new创建数组
创建数组(2):var 数组名=[] 利用字面量创建数组

数据的索引

用来访问数组元素的序号(数组下标从0开始)

获取数组元素

数组名[索引号]

新增数组元素

修改数组的长度:数组名.length=要修改的数量
追加数组的元素:数组名[索引号]=[数组元素]

数组迭代(遍历)方法

1.array.forEach(function(currentValue[,index][,arr]){})————修改原数组,不返回执行结果
 - currentValue:数组当前项的值
 - index:数组当前项索引
 - arr:数组对象本身
2.array.map(function(currentValue[,index][,arr]){})————不修改原数组,返回一个新数组;速度大于forEach
 - currentValue:数组当前项的值
 - index:数组当前项索引
 - arr:数组对象本身
3.array.filter(function(currentValue[,index][,arr]){})————筛选数组,返回一个新数组
  e.g. var newArr = arr.filter(function(value){
           return value % 2 == 0;
       });
4.array.some(function(currentValue[,index][,arr]){})————如果查找到这个元素,返回true;否则返回false
  e.g. var flag = arr.some(function(value){
           return value == 'pink';
       });
5.array.every(function(currentValue[,index][,arr]){})————检测数组所有元素是否都符合指定条件(通过函数提供)
 - 如果数组中检测到有一个元素不满足,则整个表达式返回 false,且剩余的元素不会再进行检测
 - 如果所有元素都满足条件,则返回 true
  e.g. var flag = arr.every(function(age){
           return age >= 18;
       });
  

函数的概念

在JS里面可能会定义非常多的相同代码或者功能相似的代码,这些代码可能需要大量重复使用,虽然for循环语句也能实现一些简单的重复操作,但是比较具有局限性,此时我们可以使用JS中的函数。
函数就是封装了一段,可被重复调用执行的代码块,通过此代码块可以实现大量代码的重复使用。

声明函数(1)

语法:function 函数名(){函数体}
注意事项:
1.function声明函数的关键字全部小写。
2.函数是做某件事,函数名一般是动词。
3.函数不调用自己不执行。

调用函数

语法:函数名()

函数的封装

函数的封装是把一个或多个功能通过函数的方式封装起来,对外只提供一个简单的接口。

函数的参数

形参 function 函数名(形参1,形参2){}形式上的参数接收实参
实参 函数名(实参1,实参2)  实际的参数
函数在声明时,可以在函数名称后面的小括号添加一些参数,这些参数被称为形参,而在调用该函数时,同样也需要传递相应的参数,这些参数被称为实参。
参数的作用:在函数内部某些值不能固定,我们可以通过参数在调用函数时传递不同的值进去

函数形参和实参个数不匹配的问题

实参个数等于形参个数:输出正确结果。
实参个数多于形参个数:只取道形参的个数。
实参个数小于形参个数:多的形参定义为undefined结果为NaN。

函数的返回值return

return语句:有的时候我们会希望函数将值返回给调用者,此时通过使用return语句就能实现。
语法:return 需要返回的结果(形参)

return注意事项

1.return语句之后的代码不会被执行(终止函数)
2.return只能返回一个值,如果用逗号隔开或者多个值,以最后一个为准。
3.函数没有return返回undefined
4.函数有return则返回undefined

break continue return的区别

break:结束当前的循环体(如forwhile)。
continue:跳出本次循环继续执行下次循环(如forwhile)。
retrun:不仅可以跳出循环,还能够返回return语句中的值,同时还可以结束当前的函数体内的代码。

arguments的使用

当我们不确定有多少个参数传递的时候,可以使用arguments来获取在js中Arguments,实际上它是当前函数的一个内置对象。所有函数都内置了一个arguments对象,argument对象中储存了传递所有 实参 。
arguments显示是一个为数组,因此可以进行遍历为数组具有以下特点:
1.以索引方式存储数据。
2.不具有数组push pop等方法。
3.只有 函数 才有argument对象。

声明函数(2)

语法:var 变量名 = function(){}

创建对象的三种方式

(1)利用字面量创建对象   var obj={属性1:值,属性2:值}
    1.里面的属性或方法,我们采取键值对的形式,键(属性名):值(属性值)
    2.多个属性或方法,中间用逗号隔开
    3.方法冒号后面跟的是一个匿名函数
(2)利用new Object创建对象
    var star = new Object();  //通过内置构造函数Object创建对象,此时star已经保存了创建出来的空对象
(3)利用构造函数创建对象
    function 构造函数名(形参1,形参2,形参3){  
        this.属性名1 = 参数1;  
        this.属性名2 = 参数2;  
        this.属性名3 = 参数3;  
        this.方法名 = 函数体;  
    }
    var obj = new 构造函数名(实参1,实参2,实参3)  //obj即构造函数创建出来的对象

使用对象

1.调用对象的属性我们采用 对象名.属性名
例:alert(ojb.uname)
2.调用属性还有一种方法  对象名["属性名"]
例:alert(obj["age"])
3.调用对象函数的方法  对象名.函数名()
例:obj.getkey()

构造函数

构造函数是一种特殊的函数,主要用来 初始化对象 ,即为对象成员变量赋初始值,它总与new运算符一起使用。我们可以把对象中一些公共属性和方法抽取出来,然后封装到这个函数里面。
语法格式:
function 构造函数名(){
         this.属性=值
         this.方法=function(){}
}
使用构造函数:new 构造函数名()
注意事项:构造函数名首字母要 大写 ,构造函数不需要return,调用构造函数必须使用new属性和方法,必须添加 this 。
e.g.:
    function Star(uname,agr,sex){
    this.name=uname
    this.age=age
    this.sex=sex
    }
    var ldh=new Star("刘德华","18","男")

new关键字执行过程

1.new构造函数可以在内存中创建一个空的对象
2.this就会指向刚才创建的空对象
3.执行构造函数里面的代码给这个空对象添加属性和方法
4.返回这个对象(所以构造函数里面不需要return)

遍历对象

for...in语句用于数组或者对象的 属性 进行循环操作。
语法:for((var) 变量 in 对象){console.log([变量])}
使用for in里面的变量命名一般为k/key(不强制命名)

内置对象

内置对象就是指js语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本的必要的功能(属性和方法)
javaScript供了多个内置对象:Math Date Array String...

查文档

MDN官方网址:https://developer.mozilla.org/zh-CN

Math取随机整数方法(公式)

function getRandom(min,max){
return Math.floor(Math.random()*(max-min+1))+min   返回[min,max]之间的随机整数
}

Date日期对象

1.Date()日期对象是一个 构造函数 必须使用new来调用来创建日期对象。
2.参数常用写法 数字型2021529 或是 字符串型“2021-5-29 8:8:8” 。
3.Date实例用来处理日期和时间,获取当前时间必须实例化
var now = new Date()

日期格式化

var date = new Date() 声明日期对象函数
getFullYear()  获取当年
getMonth()     获取当月(0-11)
getDate()      获取当天日期
getDay()       获取星期几(06)
getHours()     获取当前小时
getMinutes()   获取当前分钟
getSeconds()   获取当前秒钟

四种获得总的毫秒数

date.valueOf()
date.getTime()
Date.now()
⭐+new Date()     
e.g. console.log(date.getFullYear())
     console.log(date.valueOf())

总毫秒数转换为天、时、分秒公式

d=parseInt(总秒数/60/60/24)  计算天数
h=parseInt(总秒数/60/60%24)  计算小时
m=parseInt(总秒数/60%60)     计算分钟
s=parseInt(总秒数%60)        计算当前秒数

检测是否为数组

1.instanceof运算符     语法:数组名 instanceof Array
2.Array.isArray()⭐   语法:Array.isArray(数组名)
提示:第二种(更优)是H5新增的 IE9以上才可以用

添加数组元素

1.push()在数组中的 尾末 添加一个或多个数组元素
(1)push()可以给数组追加新的元素
(2)push()参数直接写数组元素
(3)push()完毕之后返回的结果写新的长度
(4)原数组也会发生变化
2.unshift()在数组 开头 添加一个或多个数组元素
e.g.:数组名.push(5,"1")

删除数组元素

1.pop()
(1)pop()可以删除数组的 最后一个 元素,一次只能删除一个元素
(2)pop()没有参数
(3)pop()完毕后返回的结果是删除的那个元素
(4)原数组也会发生变化
2.shift()删除数组 第一个 元素
e.g.:数组名.pop()

数组排序

1.reverse() 翻转数组   语法:数组名.reverse()
2.sort() 冒泡排序      语法:数组名.sort()

sort解决方案

var arr1=[13,4,76,1,2];
arr1.sort(function(a,b){
    return a-b;
})
a-b升序排序   b-a降序排序

数组索引方法

1.indexOf(str,index) 作用:返回str(字符或字符串)的索引号,从索引号为index的位置开始(可忽略该值)
(1)从前往后
(2)只满足第一个满足条件的索引号
(3)如果在该数组里面找不到元素,则返回-1
2.lastIndexOf(str,index)作用:返回str(字符或字符串)的索引号,从索引号为index的位置开始(可忽略该值)
(1)从后往前
(2)只满足第一个满足条件的索引号
(3)如果在该数组里面找不到元素,则返回-1
3.str[index]:获取指定位置处字符
  charAt(index):返回指定位置(index)的字符,和str[index]等效
    e.g. str.charAt(0);
  charCodeAt(index):返回指定位置(index)字符的ASCII码
  目的:判断用户按下了哪个键
    e.g. str.charCodeAt(0);

数组转换为字符串

1.tostring()      语法:数组名.tostring()
2.join(分隔符)     语法:数组名.join(" / - / &...")

字符串转换为数组

1.split(分隔符)

字符串操作方法

1.concat():用于连接两个或多个字符串,拼接字符串等。(+更常用)
2.slice(start,end):截取数组(start,end]  (不会改变原数组)
  从start位置开始(索引号),end结束,返回被截取项目的新数组。
3.substring(start[,end]):截取数组(start,end]  (不接受负值)
4.splice(start,n,item1,item2...itemX):添加/删除数组中的元素  (会改变原数组)
  从start位置开始(索引号),要删除的个数为n,item1...itemX为要添加到该位置的新元素,如果删除了元素则返回被删除项目的数组
5.replace(被替换的字符,替换为的字符)————只会替换第一个字符
6.trim()————返回一个两端删除空白字符(空格、制表符tab、换行符...)的新字符串

字符串的不可变

指的是里面的值不变,虽然看上去可以改变内容,但其实是地址变了,内存中新开辟了一个内存单元空间
​
var str = 'abc';
str = 'hello';  //当重新给str赋值时,常量'abc'不会被修改,依然在内存中
(重新给字符串赋值会在内存中开辟新的空间————字符串的不可变)
由于字符串的不可变,大量拼接字符串的时候会有 效率问题 :
var str = '';
for(var i = 0; i < 100000; i++){
 str += i;
}
console.log(str);    //这个结果需要花大量的时间来显示,因为需要不断地开辟新空间

包装数据类型

为了方便操作基本数据类型,JavaScript提供了三特殊的引用类型: String、Number和Boolean。
基本包装类型就是把简单数据类型包装成复杂数据类型,这样基本数据类型就有了属性和方法。
​
var str = 'andy';
console.log(str.length);
基本数据类型包装成复杂数据类型,其执行过程如下:
1.生成临时变量,把简单数据类型包装成复杂数据类型
var temp = new String('andy');
2.将临时变量赋值给我们声明的字符变量
str = temp;
3.销毁临时变量
temp = null;

获取元素的方式

1.根据ID获取元素               2.根据标签名获取
3.通过HTML5新增的方法获取       4.特殊元素获取
​
⭐console.dir(obj):打印返回的元素对象,以便更好的查看里面的属性和方法
获取元素ID: document.getElementById()
获取标签名: document.getElementsByTagName()
获取某个父元素内部所有指定标签的子元素: element.getElementsByTagName()
获取元素class: document.getElementsByClassName()
获取选择器: document.querySelector()
获取所有选择器: document.querySelectorAll()
获取body元素: document.body
获取html元素: document.doucumentElement

事件三要素

(1)事件源:事件被触发的对象,谁?e.g.按钮。
(2)事件类型:如何触发?什么事件?e.g.鼠标点击(onclick)/鼠标经过/键盘按下......
(3)事件处理程序:通过一个函数赋值的方式完成。

执行事件的步骤

(1)获取事件源
(2)注册(绑定)事件
    元素可以不用添加事件
(3)添加事件处理程序(采用函数赋值形式)

常见鼠标事件

onclick    鼠标点击左键触发  onmousedown 鼠标按下触发
onmousemove 鼠标移动触发    onmouseup  鼠标弹起触发
onmouseover 鼠标经过触发    onmouseout 鼠标离开触发
onmouseenter 鼠标经过触发   onmouseleave 鼠标离开触发
onblur   失去鼠标焦点触发    onfocus  获得鼠标焦点触发
ondblclick  鼠标双击触发
​
​
1.mouseenter和mouseover区别:
  mouseenter————不会冒泡,只有鼠标经过自身盒子触发(mouseleave同样如此)
  mouseover————会冒泡,鼠标经过自身盒子会触发,经过子盒子还会触发(mouseout同样如此)
2.如果双击文字会默认选中,此时需要双击禁止选中文字:
window.getSelection ? window.getSelection().removeAllRanges() : document.selection.empty();

操作元素

JavaScript的DOM操作可以改变页面内容结构和样式,我们可以利用DOM操作元素来改变元素里的内容、属性等。

常见的元素属性

src href id alt title 等

修改元素内容

element.innerText 改变/获取元素内容(不识别/保留html标签,同时去掉空格和换行)
element.innerHTML 改变/获取元素内容(识别/保留html标签,同时保留空格和换行)⭐

修改元素样式

1.element.style  行内样式操作————适用于样式较少/功能简单的情况
2.element.className  类名样式操作————适用于样式较多/功能复杂的情况⭐
    注意:className会直接更改(覆盖)原先的类型,若想保留原先的类名,可以使用 群组选择器
       e.g.this.className = 'origin change';(origin:原先类名)
3.element.classList————类名样式操作,用于在元素中添加、移除以及切换CSS类名⭐
添加:element.classList.add('类名');
删除:element.classList.remove('类名');
切换:element.classList.toggle('类名');  注:有就删除,无就添加

获取属性值

element.属性  //获取内置属性值(元素本身 自带 的属性)
element.getAttribute("属性") //主要获取 自定义 的属性(data-)

设置属性值

element.属性=“值” //设置内置属性值
element.setAttribute(“属性”,“值”)//设置自定义属性值(data-)

移除属性

element.removeAttribute(“属性”)
自定义属性——————为了保存并使用数据,有些数据可以保存到页面中,而不用保存到数据库中。

H5自定义属性⭐

书写规范:data-开头,做为属性名并且赋值。
        e.g.data-index1=“1”
设置方式:1.element.setAttribute('data-index',20) 
        2.<div data-index="2">(直接加在元素属性上)

H5获取自定义属性⭐

1.一个“-”连接:data-index
    (1)element.dataset.index
    (2)element.dataset['index']
2.多个"-"连接:data-list-name
    (1)element.dataset.listName(驼峰命名)
    (2)element.dataset['listName'](驼峰命名)

节点操作

节点至少拥有nodeType(节点类型)、nodeName(节点名称)和nodeValue(节点值)这三个基本属性。
 - 元素节点 nodeType:1
 - 属性节点 nodeType:2
 - 文本节点 nodeType:3(包括文字、空格、换行、注释等)
 
1.父级节点 node.parentNode⭐
  parentNode属性可以返回某节点 最近 的父节点,没有指定的节点则返回null
2.子节点
 (1)parentNode.chilNodes
     返回指定父节点的所有子节点(包括元素、文本、属性等)
 (2)parentNode.children⭐
     返回所有的子元素节点
 (3)parentNode.firstChild
     返回第一个子节点(包括所有)
 (4)parentNode.lastChild
     返回最后一个子节点(包括所有)
 (5)parentNode.firstElementChild ⬆
     返回第一个子元素节点
 (6)parentNode.lastElementChild ⬆
     返回最后一个子元素节点
 (7)parentNode.children[n]⭐
      children[0]----第一个子元素
      children[parentNode.children.length-1]----最后一个子元素
3.兄弟节点
 (1)node.nextSibling
     返回指定节点的下一个兄弟节点(包括元素、文本、属性等)
 (2)node.previousSibling
     返回指定节点的上一个兄弟节点(包括元素、文本、属性等)
 (3)node.nextElementSibling⭐
     返回指定节点的下一个兄弟元素节点
 (4)node.previousElementSibling⭐
     返回指定节点的上一个兄弟元素节点
​
document.createElement(“li”)————动态创建元素节点⭐
parentNode.appendChild(child)————添加元素节点到父节点的子节点列表末尾⭐
parentNode.inserBefore(child,指定元素)————添加元素节点到父节点的指定子元素节点前面⭐
parentNode.removeChild(child)————删除节点⭐
​
e.g. var li=document.createElement(“li”);  //1.创建元素节点
     ul.appendChild(li);                   //2.添加元素节点

阻止链接默认跳转

javascript:void(0); / javascript:;
<a href = 'javascript:; 或 javascript:void(0)'>

复制节点(克隆节点)

node.cloneNode()————返回调用该方法的节点的副本(克隆节点/拷贝节点)
e.g. var lili=ul.children[0].cloneNode(true);
     ul.appendChild(lili);
   注意:括号里为空/false是浅拷贝————只复制标签,不复制里面的内容;
       括号里为true是深拷贝————既复制标签,又复制里面的内容。

注册监听事件

同一个元素,同一个事件可以添加!多个!监听器(事件处理程序)
​
1.传统注册事件:eventTarget.onclick=function(){...};
2.监听注册事件:eventTarget.addEventListener(type,listener,[useCapture]);⭐
  该方法将指定的监听注册到eventTarget(目标对象)上,它接收三个参数:
     type:事件类型字符串,e.g. click mouseover(!!!注意这里不能带on)
     listener:事件处理函数,事件发生时会调用该监听函数( function(){...} )
     useCapture:可选参数(布尔值),默认为false
  e.g. btn.addEventListener('click',function(){...});

删除事件

1.传统解除/删除事件:eventTarget.onclick=null;
2.监听解除/删除事件:eventTarget.removeEventListener(type,listener,[useCapture]);⭐
  注意,这里的listener不能采用匿名函数,正确写法:
       div.removeEventListener('click',fn);
       function fn(){...}