1、JS组成
JavaScript: 轻量级的客户端脚本编程语言(编程语言是具备一定逻辑的,拥有自己的编程思想的) 现在的JS可以基于NODE服务器端程序,所以JS现在是全栈编程语言。
JavaScript组成:
- ECMAScript(ES):JS的核心语法
- DOM:document object model(文档对象模型),提供各种API(属性和方法)让JS可以获取或 操作页面中的HTML元素(DOM和元素)。
- BOM:browser object model(浏览器对象模型),提供各种API(属性和方法)让JS可以操作浏览器。
ECMAScript:它是JS的语法规范,JS中的变量、数据类型、操作语句、设计模式等等都是ES规定的。
2、变量(variable)和数据类型
概念: 用来存储具体值的容器或者代名词,其存储的值可变。
创建变量的六种方式:
- var(ES3)
- function(ES3)创建函数(函数名也是变量,只不过储存的值是函数类型的而已)
- let(ES6)
- const(ES6)创建的是变量
- import(ES6)基于ES6的模块规范导出需要的东西
- class(ES6)基于ES6创建类
语法示例: var [变量名]=值; (let,const…同样形式)
一些命名规范:
- 严格区分大小写
- 遵循驼峰命名法:按照数字、字母、下划线或者$来命名(数字不能开头),命名的时候基于英文单词拼接成一个完整的名字(第一个单词字母小写其余每一个有意义单词的首字母都大写)
例如:var studentInfo / student_Info / _studentInfo(下划线在前的,都是公共变量) / $studentInfo(一般存储的是JQ元素) - 不能使用关键字和保留字:在JS中有特殊含义的叫关键字,未来有可能成为关键字的叫保留字
数据类型:
- 基本数据类型(值类型):数字number ,字符串string,布尔boolean,null,undefined
类型 | |
---|---|
数字 | 其中有一个特殊的值NaN(not a number)代表的是不是一个有效的数字,但属于number类型 |
字符串 | JS中所有单引号或双引号包裹起来的都是字符串,里面色内容有零到多个字符组成 |
布尔 | true为真,false为假 |
- 引用数据类型:对象object(包含普通对象,数组对象,正则对象,日期对象,数学函数),函数function
类型 | |
---|---|
普通对象 | 由大括号包裹起来,里面包含多组属性和属性值(包括多组键值对),例如{ } 为空对象 |
数组对象 | 中括号包裹起来,包含零到多项内容 |
正则对象 | 由元字符组成一个完整的正则,/ /不是空正则是单行注释 |
- ES6中新增一个特殊类型:symbol,创建出来的是唯一的值
一些输出方式
alert输出: 基于alert输出的结果会转化为字符串,把值(如果是表达式先计算出结果)通过tostring这个方法转换为字符串然后再输出。例:
alert(1+1); =>‘2’
alert(true); =>‘true’
alert([12,23]); =>‘12,23’
alert( { name: ‘xxx’ } ); =>’ [object Objecr] ’
confirm: 和alert 用法一直,只不过它弹出的提示框有确认和取消两个按钮。
console.log: 在浏览器控制台输出日志
console.dir: 笔log输出的更加详细(尤其是输出对象数据的时候)
console.table: 把一个JSON数据按照表格的方式输出
console.group: 信息分组功能
console.assert(): 用来判断一个表达式或变量是否为真。如果结果为否,则在控制台输出一条相应信息,并且抛出一个异常
console.time()和console.timeEnd(): 用来显示代码的运行时间。
数据类型的详细剖析
- number数字类型
NaN:not a number 但是它是数字类型,它和谁都不相等,包括自己。
isNaN:检测当前数字是否不是有效数字,返回true代表不是有效数字,返回false是有效数字
isNaN检测机制:首先把当前要检测的值是否数字类型,如果不是,浏览器会默认把值转换为数字类型(其他基本类型转换为数字使用Number这个方法,引用数据类型值则先用tostring转换为字符串,再用Number将字符串转换为数字)。当前检测的值是数字类型,是有效数字返回false否则返回true。
语法示例:
isNaN(12); =>false
isNaN('汉字'); =>true
isNaN(true); =>false
isNaN(false); =>false
isNaN(null); =>false
isNaN(undefined); =>true
isNaN({age:9}); =>true
isNaN([12,23]); =>true
isNaN([12]); =>false
-
parseInt / parseFloat
等同于Number,也是为了把其他类型的值转换为数字类型,和Number的区别在于字符串转换分析上。从字符串最左边字符开始查找有效数字字符,并且转换为数字,但是一旦遇到一个非有效数字字符,查找结束。
Number:出现任意非有效数字,结果就是NaN
parseInt:把一个字符串中的整数部分解析出来
parseFloat:把一个字符串中的小数部分解析出来 -
布尔类型
如何把其他类型转换为布尔类型: Boolean,! (先把其他数据类型转换为布尔类型再取反), !! (等价于转换为布尔类型)
规律:在JS中只有“0/NaN/空字符串/null/undefined”这五个值转换为布尔类型为false,其余都为true -
null && undefined
null:空对象指针
undefined:未定义
二者区别:null一般都是意料中的没有(一般都是人为手动地先赋值为null,后面的程序会再次进行赋值),undefined代表的没有一般都不是人为手动控制的,一般都是浏览器自主为空(后面可以赋值也可不赋值) -
对象object
普通对象: 属性是用来描述当前对象特征的,属性名是当前具备这个特征,属性值是对这个特征的描述(专业语法,属性名称为键[key],属性值为[value],一组属性名和属性值称为一对键值对)
对象的操作:键值对的增删改减
var obj = {name:'Mike',age:9,0:100};
/******************************************
[获取]
语法:对象.属性 / 对象[属性]
obj.name
obj['name'] 一般来说,对象属性名都是字符串格式(属性值不固定,任何格式都可以)还有可能是数字格式
(若如遇存储属性名不是字符串也不是数字时浏览器会用tostring将其转换为字符串再存储)
obj[0]
obj['0']
不可写成obj.0
若在获取时当前对象没有这个属性则结果为undefined
[增和改]
JS对象中属性名是不允许重复,是唯一的
obj.name='Harry';//原有对象有name属性此处属于修改
obj.sex='男' ;//原有对象没有sex属性此处属于增加
[删]
彻底删除:对象中不存在这个属性
delete obj.name;
假删除:并没有一处这个属性,只是让当前这个属性为空
obj.sex=null;
*******************************************/
数组对象(对象由键值对组成)
var ary=[12,23];=> ary[0]=12,ary[1]=23
数组对象的属性名是数字(我们把数字属性名称为当前对象的索引),数组是一种特殊的对象,对象的操作对数组
也成立,也可以向其中加入字符串属性名的属性。
3、浅析JS的运行机制(堆栈内存和不同数据类型操作方式)
- 当浏览器(他的内核、引擎)渲染和解析JS的时候,会提供一个工JS代码运行的环境,我们把这个环境称之为“全局作用域(global、window)”(栈内存)
- 代码自上而下执行(之前还有一个变量提升的阶段)
· 基本数据类型的值会存储在当前作用域下,例:
var a = 12;
1)首先开辟一个空间存储12
2)在当前作用域中声明一个变量a(var a)
3)让声明的变量和存储的12进行关联(把存储的12赋值给a)=>赋值操作叫做定义
· 基本数据类型(也叫值类型),是按照值来操作:把原有的值复制一份放到新的空间或位置上,和原来的值没有关系。例:
var b = a;
1)首先开辟一个空间存储与a相等的值12
2)在当前作用域中声明一个变量b(var b)
3)让声明的变量和存储的12进行关联(把存储的12赋值给b)
· 引用数据类型的值不能直接存储到当前作用域下(因为可能存储的内容过于复杂),我们需要开辟一个新的空间(理解为仓库),把内容存储进这个空间中。例:
var obj1 = { n: 100 };
1)首先开辟一个新的内存空间(堆内存),把对象的键值对一次存储起来(为了保证后面可以找到这个空间,此空间有一个16进制的地址)
2)声明一个变量
3)让变量和空间地址关联在一起(把空间地址值赋值给变量)
· 引用类型不是按值操作,它操作的是空间引用地址:把原来空间的地址赋值给新的变量,但是原来的空间没有被克隆,还是一个空间,这样就会出现多个变量关联的是相同的空间,相互之间就会存在影响了。例:
var obj2 = obj1;
1)声明一个变量obj2
2)让变量和obj1的空间地址关联在一起 - 栈内存:本身就是一个工JS代码执行的环境,所有基本类型值都会在栈内存中开辟一个位置进行存储
堆内存:用来存储引用类型的信息值的,对象存储的是键值对,函数存储的是代码字符串 - 堆栈练习示例:
var obj{
n: 10;
m: obj.n*10;
};
console.log(obj.m); =>报错
/************************
1.形成一个
2.代码自上而下执行
3.开辟一个新的堆内存,把键值对存储到堆内存
n:10
m:obj.n*10 => 此时堆内存信息还没有存储完成,完成的地址还没有给obj,此时的obj还是undefined,
即obj.n<=>undefined.n
*************************/
var ary1=[3,4];
var ary2=ary1;
ary2[0]=1;
ary2=[4,5];
ary2[1]=2;
ary1[1]=0;
console.log(ary1,ary2); =>[1,0],[4,2]
4、JS中常见的判断操作语句
- if / else if / else
在条件判断中的tip:JS中+ - * / % 都是数学运算,除+以外,其余运算符在运算的时候,如果遇到了非数字类型的值,首先会用Number转换为数字类型然后再进行运算。+再JS中除了数学相加,还有字符串拼接的作用(如果运算中遇到了字符串,则为字符串拼接而不是数学相加)。如‘3px’+3 =>‘3px3’
JS检测数据类型方式:
1)typeof:语法 typeof [value] =>检测value的数据类型。返回值为一个字符串,字符串包含着对应的数据类型,例如:“number”/ “string” / “boolean” / “undefined” / “object”
typeof null =>“object” 因为null代表的是空对象指针。typeof检测数组、正则、对象返回的都是“object”
2)instanceof
3)constructor
4)Object.prototype.toString.call() - 三元运算符
语法:条件?成立做的事:不成立做的事; <=>简单的if / else判断
特殊情况:如果三元运算符中的某一部分不需要要做任何处理,用undefined / null / void 0占位即可
如需要执行多条操作,须将其用小括号包裹起来每条语句用逗号隔开 - switch case
应用于变量(或者表达式等)在不同值情况下的不同操作,每一种case结束后都要加break(结束整个判断)。
小区别:在switch case 每一种case的比较使用的是绝对相等(===)
例:“10”==10 =>true 相等比较,如果两边类型不一样,首先会转换为一样的数据类型,然后进行比较
“10” === 10 =>false 绝对相等比较,如果两边的数据类型不一样则直接不相等,它要求类型和值完全一样才会相等(真实项目中为了保证代码的严谨性,我们应该更多使用绝对比较)
5、JS中的循环操作语句
- for 循环
作用: 按照一定规律,重复去做某件事情,此时就需要使用循环处理
语法组成: 1.定义初始值 var i= 0; 2. 设定循环成立条件(条件成立循环继续,不成立循环结束) i < ary.length; 3.条件成立会执行循环体里的内容 4.执行步长累加的操作
关键字: continue(继续,循环体中continue后面的代码不再执行继续执行下一轮循环),break(中断或者结束,强制结束整个循环不做任何处理)
6、获取页面中的DOM元素
- document.getElementById: 在整个文档中,通过元素的属性值获取元素对象
getElementbyId是获取元素的方法,而document限定了获取元素的范围,这个范围称之为“上下文[context]”(getElementById的上下文只能是document)。如果ID重复则它只能获取到第一个(严格意义上ID是唯一的)
详析: 通过getElementbyId获取的元素是一个对象数据类型的值(里面包含很多内置的属性)一些内置属性如下
1)className:存储的是一个字符串,代表当前的样式类名
2)id:存储的是一个字符串,代表当前元素的id值
3)innerHTML:存储当前元素中所有的内容(包含HTML标签)
4)innerText:存储当前元素所有的文本内容(没有元素标签)
5)onclick:元素的一个事件属性,基于这个属性,可以给当前元素绑定点击事件
6)onmouseover:鼠标划过事件
7)onmouseout:鼠标离开事件
8)style:存储当前元素所有的行内样式 - [context].getElementsByTagNmae: 在指定的上下文中,通过元素的标签名获取一组元素集合(不管里面是否有内容,也不管有几项,它是一个容器或者集合),上下文自己指定。获取的结果是一个元素集合(HTMLcolection),首先它是对象数据类型,结构和数增速非常相似(数字作为索引,length代表长度),但是不是数组,我们把它叫做“类数组”。通过索引获得具体的一个元素。集合中的每项存储的值又是一个元素对象,包含很多内置属性
代码示例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<script>
var oBox=document.getElementById('box'); //获取到id为box的这个对象
oBox.className='bgcolor';
oBox['className']+=" bgcolor"; //修改或增加样式名称
oBox.style.backgroundColor='pink'; //通过style修改行内标签
var boxlist =oBox.getElementsByTagName('li'); //获取oBox下的标签集合
boxlist[1].style.cloor='red'; //修改集合中第二个li的文字颜色
</script>
</head>
<body>
<ul class="box" id="box">
<li>东</li>
<li>南</li>
<li>西</li>
<li>北</li>
</ul>
</body>
</html>
- getElementsByClassName: 根据class属性来获取元素,结果是一个元素集合(一个即时的NodeList(节点列表)对象),真实项目中,经常基于样式类给元素设置样式,所以在JS中也常常基于样式类来获取元素,但是此方法在IE6~8不兼容。
- getElementsByName: 根据name属性来获取元素,结果是一个节点集合,其上下文也只能是document。在IE浏览器中(IE9即以下)只对表单元素的name属性起作用(正常情况下:项目中只会给表单元素设置name属性)
tip: 获取元素可以根据标签名获取、也可以根据id、name、class属性来获取。根据id属性获取的结果是一个元素,而其它的获取的是一个集合。document对象支持以上四种,而element对象仅支持getElementsByTagName和getElementsByClassName。 - querySelector: 它返回的是匹配指定的CSS选择器的元素节点。如果有多个节点满足匹配条件,则返回第一个匹配的节点。如果没有发现匹配的节点,则返回null。querySelector方法无法选中CSS伪元素。注意,由于返回的是第一个匹配的元素,这个api使用的深度优先搜索来获取元素。(不兼容IE6~8)
示例:
<div>
<div>
<span class="test">第三级的span</span>
</div>
</div>
<div class="test">
同级的第二个div
</div>
<script>
var element = document.querySelector(".test");
alert(element.textContent);
</script>
/********************************
两个class都包含“test”的元素,一个在文档树的前面,但是它在第三级,另一个在文档树的后面,但它在第一
级,通过querySelector获取元素时,它通过深度优先搜索,拿到文档树前面的第三级的元素(文档树前面优先
深度优先)。最后输出的是:第三级的span
********************************/
- querySelectorAll: 它与querySelector不同之处在于它返回的是所有匹配的元素,querySelectorAll方法的参数,可以是逗号分隔的多个CSS选择器,返回所有匹配其中一个选择器的元素。(不兼容IE6~8)
tip: querySelector / querySelectorAll 在不考虑兼容的情况下,能用byId或者其他方法获取的,尽量也不要用这两个方法,这两个方法性能消耗较大
<div class="test">
class为test
</div>
<div id="test">
id为test
</div>
<script>
var elements = document.querySelectorAll("#test,.test");
for(var i = 0,length = elements.length;i<length;i++){
alert(elements[i].textContent);
}
</script>
/***************************
这段代码通过querySelectorAll,使用id选择器和class选择器选择了两个元素,并依次输出其内容。要注意两
点:1.querySelectorAll也是通过深度优先搜索,搜索的元素顺序和选择器的顺序无关
2.返回的是一个非即时的NodeList,也就是说结果不会随着文档树的变化而变化
***************************/
- document.head: 获取head元素对象
- document.body: 获取body元素对象
- document.documentElement: 获取HTML元素对象
// 需求:获取浏览器一屏幕的攻读和宽度(兼容所有浏览器)
document.documentElement.clientWidth || document.body.clientWidth
document.documentElement.clientHeight || document.body.clientHeight
// 在JS的当中,默认会把元素的ID设置为变量(不需要再自己设置,而且ID重复则获取的结果就是一个集合,
包含所有ID项,不重复就是一个元素对象(类似于byId获取的结果))。例如console.log(HAHA);就会输出所
有ID为HAHA的元素对象。
7、DOM元素的增删改
节点概念:
- 整个文档是一个文档节点 document
- 每个 HTML 元素是元素节点 element
- HTML 元素内的文本是文本节点
- 每个 HTML 属性是属性节点
- 解释:在一个HTML文档中出现的所有东西都是节点,包括元素节点(HTML标签),文本节点(文字内容),注释节点(注释内容),文档节点(document)等等,每一种节点都会有一些属性区分自己的特性和特征:nodeType(节点类型),nodeName(节点名称),nodeValue(节点值)等等。
- 元素节点:nodeType:1 nodeName:大写的标签名 nodeValue:null
- 文本节点:nodeType:3 nodeName:’#text’ nodeValue:文本内容(在标准浏览器中会把空格、换行等都当做文本内容)
- 注释节点:nodeType:8 nodeName:’#common’ nodeValue:注释内容
- 文档节点:nodeType:9 nodeName:’#document’ nodeValue:null
- 增加: 向HTML DOM 中添加一个新元素分为三步
1)创建要添加的新节点
2)找到要添加到的父节点
3)父节点添加新节点
描述节点之间关系的属性:
- parentNode: 获取当前节点唯一的父亲节点
- childNodes: 获取当前节点的所有子节点
- children: 获取当前元素所有元素的子节点(在IE6~8中会把注释节点也当做元素节点获取到,兼容处理)
- previousSibling: 获取当前节点的上一个哥哥节点(可能是元素节点也可能是文本等)
- previousElementSibling: 上一个哥哥元素节点(不兼容IE6~8)
- nextSibling: 获取当前节点的上一个弟弟节点
- nextElementSibling: 获取上一个弟弟元素节点(不兼容IE6~8)
- firstChild: 获取当前元素的第一个子节点(可能是元素节点也可能是文本等)
- firstElementChild: 获取当前元素的第一个元素子节点(不兼容IE6~8)
- lastChild: 获取当前元素的最后一个子节点(可能是元素节点也可能是文本等)
- lastElementChild: 获取当前元素的最后一个元素子节点(不兼容IE6~8)
// 示例一:获取当前元素的所有元素子节点
// 基于children不兼容IE低版本
/*
*children:获取当前元素的所有元素子节点
*@parameter:
* curEle:[object] 当前节点
*@return:
* [Array] 所有元素节点
*/
function children(curEle){
//1.首先获取当前元素下的所有子节点,然后筛选出元素节点(nodeType===1),把筛选出的结果存储起来即可
var nodelist = curEle.childNodes,
result = [];
for (let i = 0; i < nodelist.length; i+ +) {
var iterm = nodelist[i];
if (iterm.nodeType === 1)
result.push(iterm);
}
return result;
}
//示例2:获取当前元素的上一个哥哥节点
/*
*prev:获取当前元素的上一个哥哥元素子节点
*@parameter:
* curEle:[object] 当前节点
*@return:
* [object]: 上一个哥哥节点
*/
function prev(curEle){
//检查获取上一个哥哥节点,检查是否为元素节点,如不是基于哥哥节点再往上找哥哥节点...一直找到元素节点
//或者已经没有哥哥了则结束查找
var pre = curEle.previousSibling;
while(pre && pre.nodeType!==1){
pre = pre.previousSibling;
}
return pre;
}
DOM的增加:
向HTML DOM 中添加一个新元素分为三步
1)创建要添加的新节点
2)找到要添加到的父节点
3)父节点添加新节点
创建节点的几种API: 创建的节点只是一个孤立的节点
- createElement: 通过传入指定的一个标签名来创建一个元素,如果传入的标签名是一个未知的,则会创建一个自定义的标签。
语法: var div = document.createElement(‘div’);
tip: 通过createElement创建的元素并不属于html文档,它只是创建出来,并未添加到html文档中,要使用节点操作的方法如appendChild或insertBefore将其添加到HTML文档树中 - createTextNode: createTextNode用来创建一个文本节点
语法: var textNode = document.createTextNode(“文本内容”);
tip: createTextNode接收一个参数,这个参数就是文本节点中的文本,和createElement一样,创建后的文本节点也只是独立的一个节点,同样需要append Child将其添加到HTML文档树中 - createDocumentFragment: 创建文本片段,DocumentFragment表示一种轻量级的文档,它的作用主要是存储临时的节点用来准备添加到文档中。createDocumentFragment方法主要是用于添加大量节点到文档中时会使用到。
<ul id="list"></ul>
<input type="button" value="添加多项" id="btnAdd" />
document.getElementById("btnAdd").onclick = function(){
var list = document.getElementById("list");
var fragment = document.createDocumentFragment();
for(var i = 0;i < 100; i++){
var li = document.createElement("li");
li.textContent = i;
fragment.appendChild(li);
}
list.appendChild(fragment);
}
/*************************************************
如果每次一创建一个新的元素,然后添加到文档树中,这个过程会造成浏览器的回流。所
谓回流简单说就是指元素大小和位置会被重新计算,如果添加的元素太多,会造成性能问
题。而这里创建了一个fragment,每次生成的li节点先添加到fragment,最后一次性添
加到list
**************************************************/
Dom的删除和修改
前面提到的创建型api,它们只是创建节点,并没有真正修改到页面内容,而是要调用appendChild来将其添加到文档树中。下面是几种修改页面API
-
appendChild(追加为子元素)
-
insertBefore(插入前面)
-
cloneNode(克隆节点)
-
removeChild(删除子元素)
-
replaceChild(替换子元素)
-
set/get/removeAttribute(设置/获取/ 删除自定义属性)
appendChild: 就是将指定的节点添加到调用该方法的节点的子元素的末尾。语法为:parent.appendChild(child); child节点将会作为parent节点的最后一个子节点。需要注意的是如果被添加的节点是一个页面中存在的节点,则执行后这个节点将会添加到指定位置,其原本所在的位置将移除该节点,也就是说不会同时存在两个该节点在页面上,相当于把这个节点移动到另一个地方,如果child绑定了事件,被移动时,它依然绑定着该事件。
insertBefore: 用来添加一个节点到一个参照节点之前。
语法:parent.insertBefore(newNode,refNode);
newNode表示要添加的节点,refNode表示参照节点,新节点会添加到这个节点之前。其中refNode是必传的,如果不传该参数会报错,如果refNode是undefined或null,则insertBefore会将节点添加到子元素的末尾。
cloneNode: 把某一个节点克隆
语法:
[curEle].cloneNode() //千客隆,只克隆当前的标签
[curEle].cloneNode(true) //深克隆,单签标签及其里面内容都一起克隆了
removeChild: 在指定容器中删除某一个元素。
replaceChild: 使用一个节点替换另一个节点
二者语法示例如下:
var oldChild = node.removeChild(child);
//或者
parent.removeChild(child);
/***************************************
child 是要移除的那个子节点.
node 是child的父节点.
oldChild保存对删除的子节点的引用. oldChild === child.
被移除的这个子节点仍然存在于内存中,只是没有添加到当前文档的DOM树中,因此,仍然可以把这个节点重新添加
回文档中,只不过要用另外一个变量比如上例中的oldChild来保存这个节点的引用. 如果使用上述语法中的第二
种方法, 即没有使用 oldChild 来保存对这个节点的引用, 则认为被移除的节点已经是无用的,在短时间内将会
被内存管理回收.
****************************************/
// 先定位父节点,然后删除其子节点
var d = document.getElementById("top");
var d_nested = document.getElementById("nested");
var throwawayNode = d.removeChild(d_nested);
// 无须定位父节点,通过parentNode属性直接删除自身
var node = document.getElementById("nested");
if (node.parentNode) {
node.parentNode.removeChild(node);
}
// 移除一个元素节点的所有子节点
var parent = document.getElementById("top");
while (parent.firstChild) {
parent.removeChild(element.firstChild);
//替换节点
parent.replaceChild(newChild,oldChild);
//newChild是替换的节点,可以是新的节点,也可以是页面上的节点,如果是页面上的节点,则其将被转移到新
//的位置oldChild是被替换的节点
set/get/removeAttribute: 设置/获取/ 删除 当前元素的某一个自定义属性,其属性值都是字符串格式
var oBox = document.getElementById('box');
//把当前元素作为一个对象,在对象对应的堆内存中新增一个自定义属性
oBox.myIndex = 10; //设置
console.log(oBox['myIndex']); //获取
delete oBox.myIndex; //删除
//基于set/get/removeAttribute的方法设置自定义属性
oBox.setAttribute('myColor','red')// 设置
oBox.getAttribute('myColor'); //获取
oBox.removeAttribute('myColor'); //删除
//以上两种基于独立的运作体制。不能相互混淆使用
//第一种是基于对象键值对操作方式修改当前元素对象的堆内存空间来完成的
//第二种是直接修改页面当中HTML标签的结构来完成(此种办法设置的自定义属性可以在结构上呈现出来)
7、JS中的数据类型转换规则
- 判断: 若判断一个值得真假,遵循只有0,NaN,’’,null,undefined这五个是假的,其余的都是真的原则
- 相等比较: 如果 == 两边的数据类型不同会进行默认的数据类型转换,规则如下
1)对象== 对象:永不相等
2)对象== 字符串:用tostring把对象转换为字符串,普通对象转换后即字符串"[object,objec]"。注:[]空数组转化为字符串是’’
3)对象== 布尔类型:都转化为数字比较,对象先toString转换为字符串,然后再把字符串用Nunber转化为数字(""空字符串为0) ,布尔类型也转化为数字(true是1,false是0)
4)对象== 数字:对象先toString转换为字符串,然后再把字符串用Nunber转化为数字,最后数字进行比较
5)数字== 布尔类型:布尔转数字
6)数字== 字符串:字符串转数字(Number)
7)字符串== 布尔:都转化为数字
8)undefined== null:结果为true
9)null或者undefined 它们和自身是相等的,除此之外和其他任何值都不想等 - 绝对相等比较: 如果两边的数据类型不一样则直接不相等,它要求类型和值完全一样才会相等
- 示例:
![]->false
[]==[]->false 转换为 0==0
[]==true ->false
[]== false ->true 都转换为数字
![]== false ->true 先算![],把数组变为布尔再取反=>false =>false==false
![]==true ->false
补充:
(1)把其他数据类型转换为number
发生情况:
1、isNaN检测时浏览器会自主调用Number转换
2、基于parseInt / parseFloat / Number 手动转换
3、数学运算(+ - * / %)
(2)把其他类型转换为字符串
常用发生情况:
1、基于alert / confirm / prompt / docunment.write等方法输出内容的时候,会把值转换为字符串,然后再输出
2、基于“+”进行字符串拼接的时候
3、把引用值转化为数字时,首先会先转化为字符串
4、给对象设置属性名,如果不是字符串,数显转换为字符串,然后再当做属性存储到对象中(对象的属性只能是字符串或者数字)
5、手动调用toString / toFixed / join / String等方法时
(3)把其他值转换为布尔类型
常用发生情况:
1、基于!/ !! / Boolean等方法
2、条件判断中的条件最后均会转换为布尔类型
(4)特殊情况
数学运算与字符串拼接
//=>当表达式中出现字符串,就是字符串拼接,否则就是数学运算
1+true =>2 数学运算
'1'+true =>'1true' 字符串拼接
[12]+10 =>'1210' 虽然没有字符串,但是引用类型转换为数字,首先会先转换为字符串,所以变为了字符串
拼接
({})+10 =>'[object Object]10'
[]+10 =>'10'
{}+10 =>10 这个既不是数学运算也不是字符串拼接,它是两部分代码,{}代表一个代码块(块级作用域),
+10才是真正的操作。严格写法:{}; +10;
12+true+false+null+undefined+[]+'字符'+null+undefined+[]+true =>'NaN字符nullundefinedtrue'
8、常见数组方法
- 添加与删除
方法 | 功能描述 |
---|---|
push() | 将一个或多个元素添加到数组的末尾,参数为添加元素,并返回数组的新长度 |
unshift() | 将一个或多个元素添加到数组的开头,参数为添加元素,并返回数组的新长度 |
pop() | 从数组的末尾移出并返回最后一个元素,若是空数组则返回undefined,无参 |
shift() | 从数组的开头移出并返回第一个元素,若是空数组则返回undefined,无参 |
注:以上四种方法均改变了原数组长度 |
- splice(): 可以实现增删改
删除功能: splice(index,count) index为开始位置的索引 count为要删除元素的个数,把删除的内容以新数组返回,原有数组改变,如果不指定count或删除个数大于最大长度则直接删除到末尾
插入功能: splice(index,0,插入项) index为插入元素的索引值,把插入项(可以为多项)存放进索引index的前面,返回结果为空数组
修改功能: splice(index,num,value) index:开始的索引位置 num:删除项的数(如果num为0,就是插入功能) value:插入的值 返回:返回的是包含被删除的元素的数组对象。修改原理即为把原有内容删除后再用新内容替换
var arr=[1,2,3,4,5,6,7,8];
arr.splice(2,0,100);//arr=[1,2,100,3,4,5,6,7,8]
var arr1=arr.splice(2,1);//删除时返回的删除元素的数组,arr1=[100],原数组也被修改
var arr2=arr.splice(2,2);//arr2=[1,2,5,6,7,8]
var arr3=arr.splice(2,1,3);//arr3=[5],arr=[1,2,3,6,7,8]
小结:
删除最后一项
ary.pop();
ary.splice(ary.length-1);
ary.Length--;
向数组末尾追加新内容
ary.push(100);
ary.splice(length,0,100);
ary[length]=100
- slice(begin,end): 对一个数组按条件查找出其中部分内容,执行后返回一个新的数组,不会对原数组产生影响。
begin: 从该索引处开始提取原数组中的元素,如果该参数为负数,则表示从原数组中的倒数第几个元素开始提取,slice(-2)表示提取原数组中的倒数第二个元素到最后一个元素(包含最后一个元素)。如果省略 begin,则 slice 从索引 0 开始。
end: 在该索引处结束提取原数组元素(从0开始)。slice会提取原数组中索引从 begin 到 end 的所有元素(包含begin,但不包含end)。
slice(1,4) 提取原数组中的第二个元素开始直到第四个元素的所有元素 (索引为 1, 2, 3的元素)。如果该参数为负数, 则它表示在原数组中的倒数第几个元素结束抽取。 slice(-2,-1)表示抽取了原数组中的倒数第二个元素到最后一个元素(不包含最后一个元素,也就是只有倒数第二个元素),索引为length加上负索引。如果 end 被省略,则slice 会一直提取到原数组末尾。如果 end 大于数组长度,slice 也会一直提取到原数组末尾。
var arr=[1,2,3,4,5,6,7,8];
var arr1=arr.slice();//无参时进行一个简单的复制
var arr2=arr.slice(1);//从第二个元素(即索引号为1)开始复制,arr2=[2,3,4,5,6,7,8]
var arr3=arr.slice(-3);// 抓取倒数三个元素,arr3=[6,7,8]
var arr4=arr.slice(0,4);//抓取前四个元素,arr4=[1,2,3,4]
- concat(): 可以将多个数组(或者值)拼接成一个数组,参数是数组,返回的也是一个拼接后的数组,原有数组不变
var arr1 = [1, 2, 3];
var arr2 = [4, 5];
var arr = arr1.concat(arr2);
// arr=[1,2,3,4,5]
var arr3=arr1.concat(ary2,'字符');
// arr3=[1,2,3,4,5,'字符']
- sort(): 给数组排序,无参或者传函数,返回排序后的新数组原有数组改变。在不传参数的时候只能处理10以内的数字排序(它是先排第一位,第一位相同再排第二位)
var ary1=[1,3,5,6,8,2,4,7,9];
ary1.sort(); ->ary1=[1,2,3,4,5,6,7,8,9]
var ary2=[18,1,23,27,2,35,3,56];
ary2.sort(); ->ary2=[1,18,2,23,27,3,35,56];
//真实项目中基于sort排序需要传递参数
ary2.sort(function(a,b){
return a-b; //升序
return b-a; //降序
})
- map(): 将数组中的每个元素调用一个提供的函数,结果作为一个新的数组返回,并没有改变原来的数组
var arr = [1, 2, 3, 4, 5];
newArr = arr.map(x => x*2);
//arr= [1, 2, 3, 4, 5] 原数组保持不变
//newArr = [2, 4, 6, 8, 10] 返回新数组
- forEach(): 将数组中的每个元素执行传进提供的函数,没有返回值,直接改变原数组,注意和map方法区分
var arr = [1, 2,**加粗样式** 3, 4, 5];
arr.forEach(x => x*2);
// arr = [2, 4, 6, 8, 10] 数组改变
- filter(): 将所有元素进行判断,将满足条件的元素作为一个新的数组返回,可能会改变数组
- every(): 将所有元素进行判断返回一个布尔值,如果所有元素都满足判断条件,则返回true,否则为false,不改变数组。
- some(): 将所有元素进行判断返回一个布尔值,如果存在元素都满足判断条件,则返回true,若所有元素都不满足判断条件,则返回false,不改变数组
- reduce(): 所有元素调用返回函数,返回值为最后结果,传入的值必须是函数类型
var arr=[1,2,3,4,5];
const add = (a, b) => a + b;
var sum = arr.reduce(add);
//sum=15,相当于累加
-
Array.isArray(): 判断一个对象是不是数组,返回的是布尔值 ,不改变数组
-
indexOf() / lastIndexOf(): 返回在数组中可以找到给定值的第一个索引 / 最后一个索引 ,参数为要检测的值,如果不存在,则返回-1,原有数组不变
-
includes(): 用于确定数组中是否含有某个元素,含有返回true,否则返回false。
-
toString(): 将数组转化为字符串,返回一个字符串
-
join(): 将数组的所有元素连接到一个字符串中,返回的也是一个字符串
var arr=[1,2,3,4,5];
var str1=arr.toString();//str1:'1,2,3,4,5'
var str2=arr.join();//str2:'1,2,3,4,5'
var str3=arr.join('#');//str3:'1#2#3#4#5'
var str4=arr.join('+');//str4:'1+2+3+4+5'
var sum=eval(str4);//sum=15 用eval可以将字符串转换为JS表达式执行,可以实现数组求和
/************************************
join()和toString()方法的相同点:
可将多维数组转为字符串,默认情况下使用逗号连接。
当数组元素为undefined、null或空数组时,对应的元素会被转换为空字符串
join()和toString()方法的不同点。
join()方法可以指定连接数组元素的符号。
************************************/
- fill(value, start, end): 用一个固定值填充数组中指定下标范围内的全部元素,返回为数组,原数组改变。
value:填充值。
start:填充起始位置,可以省略。
end:填充结束位置,可以省略,实际结束位置是end-1,end位不被填充
var arr=[1,2,3,4,5,6,7,8];
var arr1=arr.fill(7);//省略后两个参数,则全部填充。arr1=[7,7,7,7,7,7,7,7]
var arr2=arr1.fill(6,2,5)//索引号从2到5填充为6(包括2不包括5) arr2=[7,7,6,6,6,7,7,7,7]
var arr3=arr2.fill(8,2)//省略第三个参数 arr3=[7,7,8,8,8,8,8,8ccc]
- reverse(): 颠倒数组中元素的位置原数组元素倒序排列 该方法会改变原来的数组,而不会创建新的数组。
9、数组去重
1. 双重循环: 先定义一个包含原始数组第一个元素的数组,然后遍历原始数组,将原始数组中的每个元素与新数组中的每个元素进行比对,如果不重复则添加到新数组中,最后返回新数组;因为它的时间复杂度是O(n^2),如果数组长度很大,将会非常耗费内存.
function unique1(arr) {
// 判断是否是数组
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
let res = [arr[0]]
for (let i = 1; i < arr.length; i++) {
let flag = true
for (let j = 0; j < res.length; j++) {
if (arr[i] === res[j]) {
flag = false;
break
}
}
if (flag) {
res.push(arr[i])
}
}
return res
}
function unique2(arr){
for (let i = 1; i < arr.length-1; i++){
var iterm=arr[i];
for (let k = i+1; k < arr.length; k++){
if(iterm===arr[k])
// arr.splice(k,1); 这么写会导致数组塌陷,原有数组的索引会发生改变
arr.splice(k,1);
k--; //先减再加,k岁没变,但数组塌陷了,其余元素的索引会减小
}
}
}
2.indexOf去重: 基本思路是新建一个数组,原数组遍历传入新数组,判断值是否存在,值不存在就加入该新数组中
function unique1(arr){
//一个新的数组
var res = [];
//遍历当前数组
for(var i = 0; i < arr.length; i++){
//如果临时数组里没有当前数组的当前值,则把当前值push到新数组里面
if (res.indexOf(arr[i]) == -1){
res.push(array[i])
};
}
return arrs
}
function unique2(arr){
var res = [];
//遍历当前数组
for(var i = 0; i < arr.length; i++){
//
if (arr.indexOf(arr[i]) == i){
res.push(array[i])
};
}
return res
}
- 利用ES6中的Set去重: Array.from方法可以将Set结构转换为数组结果,而set结果是不重复的数据集,因此能够达到去重的目的.
function unique(arr) {
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
return Array.from(new Set(arr))
}
- 利用对象属性去重: 创建空对象,遍历数组,将数组中的值设为对象的属性,并给该属性赋初始值1,每出现一次,对应的属性值增加1,这样,属性值对应的就是该元素出现的次数了.
function unique(arr){
if (!Array.isArray(arr)) {
console.log('type error!')
return
}
let res=[];
let obj={};
for (var i=0;i<arr.length;i++){
if (!obj[arr.[i]]){
res.push(arr[i]);
obj[arr[i]] = 1;
}else{
obj[arr[i]]++
}
}
return res;
}
9、JS字符串方法
- charAtz(index): 返回指定索引处的字符,不改变原字符串,index取值范围[0,str.length-1]
var str='abcd';
var a=str.charAt(0);
console.log(a); //'a'
console.log(str); //'abcd'
- charCodeAt(index): 返回子字符串的unicode编码,index取值范围同上
- indexOf(searchString,startIndex): 返回子字符串第一次出现的位置,从startIndex开始查找,找不到时返回-1
var str='abcd';
str.indexOf('a'); //0
str.indexOf('e'); //-1
- lastIndexOf(searchString,startIndex): 判断一个字符最后一次出现在某个字符串的索引,如果包含返回它的索引,如果不包含返回-1.
var str='abcdb';
str.lastIndexOf('b'); //4
str.lastIndexOf('e'); //-1
- concat(): 拼接2个字符串,返回一个新字符串,对原有字符串没有任何改变。
var str='qwe';
var str1='abc';
var str2=str.concat(str1);// 'qweabc'
- substr(n,m): n可正可负,负值代表从右截取,从索引n开始,截取m个字符,将截取的字符返回,对原字符串没有任何改变。
var str='abcdb';
var b=str.substr(1,1)
console.log(b); // 'b'
- substring(n,m): 两个参数都为正数,从索引n开始,截取到索引m,不包括m.将截取的字符返回,对原字符串没有任何改变.
var str='abcdb';
var str1=str.substring(1,3);
console.log(str1); //"bc"
- slice(n,m): 两个参数可正可负,负值代表从右截取,从索引n开始,截取到索引m,不包括m.将截取的字符返回,对原字符串没有任何改变.
- split(separator,limit): 参数1指定字符串或正则,参照2指定数组的最大长度。用指定字符分割字符串,返回一个数组.对原字符串没有任何改变。
str='abcd';
var a=str.split('');
console.log(a); //["a", "b", "c", "d"]
- replace(rgExp/substr,replaceText): 替换指定字符,返回替换后新的字符串,对原有字符串有改变。(第一个参数可以是正则表达式) 只能替换一次 ,配合正则模式修饰符g使用。
var str='aaaaee';
var reg=/a/g;
str.replace(reg,1); //"1111ee"
- match(): 可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。把找到的字符放在数组里,返回一个数组。
var str='aaaa3ed33';
var reg=/a/g;
str.match(reg); //["a", "a", "a", "a"]
- search( ): 跟indexOf相似,它可以检索一个子字符串在整个字符串中的位置,除此之外,它还能够接收一个正则表达式,进行检索。如果找到则返回子字符串出现的位置,如果找不到则返回-1。这个方法对大小写敏感。
var str='abcdefg'
alert(str.search('c')); //2
alert(str.search('u')); //-1
alert(str.search('C')); //-1
alert(str.search(/c/i)); //2
- 字符串比较。依次比较两个字符串中的对应字符的unicode编码,一旦有一位比较出结果
alert('a'>'b');//false,b是98,a是97
alert('ab'>'b');//false
alert('ba'>'ab');//true
//实战需求
//一、时间字符串格式化:把一个时间字符串例如“2018-4-4 16:26:8”,基于此获取到“4月4日 16时26分”
/*
* 1.基于split按照空格把字符串拆成两部分(数组中的两项)
* 2.左边这一部分继续以split按照杠号拆
* 3.左边这一部分继续以split按照冒号拆
* 4.把需要的信息拼接在一起(拼接的时候不足十位的补0)
*/
function addZero(val){
return val<10 ? '0'+val : val;
}
var str = '2018-4-4 16:32:8';
var ary = str.split(' '),
aryLeft = ary[0].split('-'), //=>['2018','4','4']
aryRight = ary[1].split(':'); //=>['16','32','8']
var month = addZero(aryLeft[1]),
day = addZero(aryLeft[2]),
hour = addZero(aryRight[0]),
minute = addZero(aryRight[1]);
var result = month + '月' + day + '日' + hour + '时' + minute + '分';
//二、URL地址栏问号传参解析
/*有一个URL地址“http://www.zhufengpeixun.cn/stu/?lx=1&name=AA&sex=man”地址问号后面的内容是需
* 要解析出来的参数信息
* {
* lx:1,
* name:'AA',
* sex:'man'
*/
}
/*
* 1.先找到问号,把问号后面的信息截取下来即可
* 2.首先验证是否存在哈希值,存在则从问号开始截取到#,不存在则直接截取到字符串末尾
* 3.以&进行拆分
* 4.遍历数组每一项,把每一项再按照=进行拆分,把拆分后第一项作为对象的属性名,第二项作为属性值存储
*/
var str = 'http://www.zhufengpeixun.cn/stu/?lx=1&name=AA&sex=man#teacher';
//#后面的称为哈希(HASH)值,可能有可能没有,截取是需要过滤掉
var indexASK = str.indexOf('?'),
indexWell = str.indexOf('#');
if (indexWell>-1){
//有#截取到#为止
str = str.substring(indexASK+1,indexWell);
}else{
str.substr(indexASK+1);
}
var ary = str.split('&'),
obj = {};
for (let i = 0; i < ary.length; i++) {
var itermAry = ary[i].split('=');
obj[itermAry[0]] = itermAry[1];
}
10、Math库的方法
名称 | 描述 |
---|---|
Math.min() | 确定一组数值中的最小值 |
Math.max() | 确定一组数值中的最大值 |
Math.ceil() | 向上舍入,即它总是将数值向上舍入为最接近的整数 |
Math.floor() | 向下舍入,即它总是将数值向下舍入为最接近的整数 |
Math.round() | 即它总是将数值四舍五入为最接近的整数; |
Math.random() | 取[0,1)的随机小数.例:Math.round(Math.random()*(m-n)+n) 获取[n,m]之间的随机整数 |
Math.abs(num) | 返回num的绝对值 |
Math.exp(num) | |
Math.log(num) | 返回num的自然对数 |
Math.pow(num,power) | 返回num的power次幂 |
Math.sqrt(num) | 返回num的平方根 |
Math.cos(x) | 返回x的余弦值(其余两个同理) |
Math.acos(x) | 返回x的反余弦值(其余两个同理) |
Math.atan2(y,x) | 返回y/x的反正切值 |
Math.PI | 获取圆周率π 的值 |
exp(x) | 返回 e 的指数。 |