JavaScript基础知识
一、对象的使用
1、创建对象
这里创建对象的方法我们采用最常用的一种:
//第一种
<script>
var Person = {
name: "zhangsan",
age: "19",
weight: "140",
hight: "170",
print:function(){
console.log("hi");
}
};
</script>
//第二种
<script>
var obj = new Object();//创建了一个空的对象
obj.name = "zhangsan";
obj.age = 19;
obj.sayHi = function () {
alert("hi");
}
</script>
//第三种,利用构造函数创建对象
/*
//构造函数的语法格式
function 构造函数名(){
this.属性名1 = 属性值1;
this.属性名2 = 属性值2;
this.属性名3 = 属性值3;
this.方法名 = function(){}
}
//调用构造函数创建对象
new 构造函数名();
*/
script>
function Star(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sing = function () {
alert("情深深雨濛濛")
}
}
var ldh = new Star("刘德华", 50, "男");
ldh.sing();
</script>
注意这里在声明对象里面的方法的时候和之前说的不一样!!!
2、 调用属性和方法
<script>
var Person = {
name: "zhangsan",
age: "19",
weight: "140",
hight: "170",
print: function () {
alert("hi")
}
};
document.write(Person.name);
document.write(Person.print())
</script>
3、遍历对象
<script>
var obj = {
name: "zhangsan",
age: 18,
sex: "man"
}
for (var k in obj) {
console.log(k);//这个是属性名
console.log(obj[k]);//这个就是属性值
}
</script>
二、JavaScript中的内置对象
1、Math对象
<script>
//Math不是一个构造函数,不需要new对象来使用
//圆周率 Math.PI
//最大值 Math.max(1,54,9); //54
//Math.max(1,54,"asda"); //NaN
//Math.max(); //-Infinity
//绝对值 Math.abs(-1); ----1
//绝对值 Math.abs('-1'); ----1 隐式转换,会把字符类型的数据转换为数字类型
绝对值 Math.abs('asfdia'); ---- NaN
//向下取整 Math.floor(1.9); ----1
//向上取整 Math.ceil(1.1); ----2
//四舍五入 Math.round(1.1); ---
//随机数
Math.random();// 此函数返回一个浮点数,返回一个[0,1)的数值
console.log(Math.random() * 100);
//得到两个数之间的随机数,并且包含这两个数
function getRandom(min, max) {
console.log(Math.floor(Math.random() * (max - min + 1)) + min);
}
getRandom(1, 10);
</script>
①、猜数字游戏
<script>
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
var randomNumber = getRandom(1, 10);
while (true) {
var inputNumber = +prompt("请输入一个整数");
if (randomNumber > inputNumber) {
alert("猜小了");
} else if (randomNumber < inputNumber) {
alert("猜大了");
} else {
alert("猜对了");
break;
}
}
</script>
2、Date对象
创建一个Date对象
var d = new Date();//表示当前代码执行的时间
//创建一个指定的时间对象
//需要在构造函数中传递应该表示时间的字符串作为参数
var d = new Date("12/03/2024 12:22:54");
//日期的格式:月/日/年 时/分/秒
①、常用的方法
var d = new Date();
d.getDate();//获取当前的日期是几号
d.getDay();//返回日期是一周中的哪一天,0-6,0表示周日
d.getMonth();//获取月份。0-11,0表示一月,11表示12月
d.getFullYear();//获取年份
//时间戳指,1970年1月1日 0时0分0秒到当前日期所花的毫秒数
d.getTime();//获取当前日期对象的时间戳
//获取当前的时间戳
time = Data.now();
/*
利用时间戳来测试代码的执行时间
var start = Date.now();
for(var i = 0;i<100;i++){
console.log(i);
}
var end = Date.now();
console.log(end-start);
*/
3、String对象
在底层字符串时以字符数组的形式保存的,下标从0开始
①常用的方法
var str = "hello world";
str.length;//是记录字符串的长度
str.charAt();//返回字符串中指定位置的字符
str.charCodeAt();//返回指定位置字符的unicode编码
String.fromCharCode();/根据字符编码区获取字符,得通过构造函数对象调用
str.concat();//用来连接两个或者多个字符串
str.indexOf();//该方法可以检索一个字符串中是否含有指定内容,如果字符串中含有该内容,则会返回其第一次出现的索引,如果没有,则返回-1,例:str.indexOf("h");
str.indexOf("d",0);//这第二个参数就是指定从第几次出现这个字符的位置开始查找,0表示从第一次指定字符出现的位置开始查找,1表示第二次
str.lastIndexOf();//该方法的和indexOf方法一样,只不过indexOf从前往后,lastIndexOf从后往前,也可以指定第二个参数
str.slice(0,2);//从字符串中截取指定的内容,不会影响原字符串,第一个参数是开始位置的索引(包括开始位置),第二个参数是结束位置的索引(不包括结束位置),如果省略第二个参数,则截取第一个参数后面所有的
str.substring();//也可以截取字符串,第一个参数是开始位置的索引(包括开始位置),第二个参数是结束位置的索引(不包括结束位置),如果省略第二个参数,则截取第一个参数后面所有的;但是不同的是,这个方法不能接收负值,有负值表示0
str.substr(1,2);//
//参数:
1:截取开始位置的索引,
2:截取的个数
str.split(",");//需要一个字符串作为参数,根据参数去拆分数组,返回值是一个数组
4、正则表达式
正则表达式用于定义一些字符串的规则:
①计算机可以根据正则表达检查一个字符串是否符合规则
//创建正则表达式的对象
/*
语法:
var 变量名 = new RegExp("正则表达式","匹配模式");
使用typeof检查正则对象,会返回object
在构造函数中,可以传递一个匹配模式作为第二个参数
可以是:
i:忽略大小写
g:全局匹配模式
*/
正则表达式的方法:
test();
用来检查一个字符串是否符合正则表达式的规则,符合返回true,否则返回false
<script>
var reg = new RegExp("a");//这个正则表达式用来检查字符串中是否含有a
var str = "abc";
var ret = reg.test(str);
console.log(ret); // true
var reg = new RegExp("A","i");//这个正则表达式用来检查字符串中是否含有a
var str = "Abc";
var ret = reg.test(str);
console.log(ret); // true
</script>
②可以使用字面量创建正则表达式
/*
①使用字面量创建正则表达式
var 变量名 = /正则表达式/匹配模式
例:
<script>
var reg = /a/i
console.log(reg.test('bc'))//false
console.log(reg.test('ABC'))//true
console.log(reg.test('abc'))//true
</script>
②创建一个正则表达式用来检测字符串中是否有a或者b,使用|,或者使用[],[]里面的内容也是或者的意思,[bc]就是b或者c的意思
<script>
var reg = /a|b/i
console.log(reg.test("a"))
console.log(reg.test("bc"))
</script>
③创建一个正则表达式用来检测字符串中是否有字母
<script>
//[a-z]表示任意的小写字母,[A-Z]表示任意的大写字母,[A-z]表示任意的字母,[0-9]表示任意数字
var reg=/[a-z]/
console.log(reg.test('a'))//true
console.log(reg.test('A'))//false
</script>
④创建一个正则表达式用来检测字符串中是否有abc或者adc或者aec
<script>
var reg = /a[bde]c/
console.log(reg.test('abc'))//true
console.log(reg.test('adc'))//true
console.log(reg.test('acd'))//false
console.log(reg.test('abd'))//false
console.log(reg.test('abf'))//false
</script>
⑤[^ ]表示除了
<script>
var reg=/[^ab]/
console.log(reg.test("abc"));//true
</script>
*/
③字符串和正则表达式一起使用
/*
split()
- 可以将一个字符串拆分成一个数组
- 方法中可以传一个正则表达式作为参数,这样的方法将会根据正则表达式去拆分字符串
例:根据任意的字符将字符串进行拆分
注意:
这个方法不指定全局匹配都会给拆完
<script>
var str = "1a2b3c4d5f6e7";
var ret = str.split(/[A-z]/);
console.log(ret.length);
</script>
search()
例:可以搜索字符串中是否含有指定内容
<script>
var str = "hello abc bcd hello";
var ret = str.search("abc");
console.log(ret);//等于6,是从下标0开始数的
//如果搜索到指定内容返回第一次出现的索引,否则返回-1,他可以接受正则表达式去检索字符串
注意:
search只会查找第一个,即使设置了全局匹配
例:搜索字符串中是否含有abc 或者 aec或者 afc
var str = "hello abc bcd afc aec";
var ret = str.search(/a[bef]c/);
</script>
match()
可以根据正则表达式,从一个字符串中符合条件的内容提取出来
注意:
一般情况下match只会找到第一个符合要求的内容,找到以后就停止检索,我们可以设置正则表达式为全局模式(写一个g),这样就会匹配到所有的内容
可以为一个正则表达式设置多个匹配模式,且不用在意顺序
match会将匹配到的内容封装到一个数组中,即使只有一个查询结果
var str = "1a2b3c4d5f6e7";
var ret = str.match(/A-z/);
replace(参数1,参数2)
可以将字符串中指定的内容替换为新的内容
参数1:被替换的内容:可以接受一个正则表达式
参数2:新的内容
注意:
默认只会替换第一个
var str = "1a2b3c4d5f6e7";
var ret = str.replace("a","@_@");
ret = str.replace(/a/gi,"@_@");
*/
④量词
- 通过量词可以设置一个内容出现的次数,{a}表示正好出现n次
var reg = /a{3}/;//这个就是aaa的表达
- 注意:量词只对前面一个内容起作用
- {m,n}表示出现m到n次
- {m,}表示m次以上
- +表示至少一个,即{1,}
- *表示0个或者多个,相当于{0,}
- ?0个或者1个,相当于{0,1}
⑤检查一个字符串是否以一个字符开头或者结尾
-
使用^+字符
var reg = /^a/;//就是检查字符串是否是以一个字符开头
-
使用字符+$
var reg = /a$/;//检查字符串是否是以指定字符结尾
-
即使用^,有使用$
var reg = /^a$/;表示在正则表达式中只能有这个字符串
var reg = /^a|a$/;表示以a为开头或者以a结尾
⑥使用正则表达式检查电话是否符合规则
<script>
var str = "18882636878";
var reg = /^1[3-9][0-9]{9}$/;
/*
手机号规则:
第一位以1开头
第二位以3-9中的数字开头
第三位及其以后只要是数字就行,但是最后必须以数字结尾
*/
console.log(reg.test(str));
</script>
⑦检查一个字符串中是否含有.
- 但是在正则表达式中,光是写点表示任意字符
- 像这样的还有很多
- 表示\:使用两个\,即\
- 表示.:使用.
- \w:表示任意字母、数字、__
- \W:表示除了字母、数字、__
- \S:除了空格
- \s:表示空格
- \D:除了数字
- \d:任意的数字,0-9
- \B:除了单词边界
- \b:单词边界
- 创建一个正则表达式检测一个字符串中是否含有单词child
var reg = /\bchild\b/;
注意:使用构造函数的时候,由于它的参数是一个字符串,而\是字符串中转义字符,如果要使用\,就必须使用\\来代替
var str = "a.";
var reg = /\./;//要使用转义字符
console.log(reg.test(str));//true
⑧去除空格
- 去除字符串前后的空格
- 去除空格就是使用“”来替换空格
<script>
var str = " hel lo ";
//去除开头的空格
var str = str.replace(/^\s*/, "");
//去除结尾的空格
var str = str.replace(/\s*$/, "");
//去除两端的空格
var str = str.replace(/^\s*|\s*$/g, "");
console.log(str);
</script>
⑨判断一个字符串是否是电子邮件
<script>
/*
电子邮件
任意字母数字下划线 .任意字母数字下划线 @ 任意字母数字 . 任意字母(2-5位)
*/
var reg = /^\w{3,}(\.\w+)*@[A-z0-9]+(\.[A-z]{2,5}){1,2}$/;
var email = "2326709846@qq.com";
console.log(reg.test(email));
</script>
三、DOM对象
节点
- 文档节点:整个html文档
- 元素节点:html文档中的html标签
- 属性节点:元素的属性
- 文本节点:html标签中的文本内容
<body>
<button id="butId" name="btn">我是按钮</button>
</body>
<script>
//通过id获取元素
var but = document.getElementById("butId");
//修改元素内容
but.innerHTML = "我是一个大but";
//通过name属性获取元素
var btn = document.getElmentsByName("btn");
//通过标签名获取元素
var btn = document.getElementsByTagName("button");
</script>
1、事件
//点击事件,当用户点击按钮,就会弹出对话框
<button id="butId" onclick="alert('你点我干嘛')">我是按钮</button>
//双击事件
<button id="butId" ondblclick="alert('你点我干嘛')">我是按钮</button>
//鼠标移动事件
<button id="butId" onmousemove="alert('你别动')">我是按钮</button>
但是以上的写法,不推荐使用
请看在script标签里面的处理事件
<body>
<button id="btnId">我是按钮</button>
</body>
<script>
//获取按钮对象
var btn = document.getElementById('btnId');
//绑定单击事件
btn.onclick = function () {
alert('按钮被点击了');
}
</script>
2、获取元素节点的子节点
<body>
<ul id="city">
<li>成都</li>
<li>北京</li>
<li>上海</li>
<li>广州</li>
</ul>
</body>
<script>
//获取所有的子元素的节点
var city = document.getElementById("city");
var lis = city.childNodes;
/*
这里的childNodes方法会获取包括文本节点在内的所有节点,注意并不是只有标签
这里的文本节点就是回车键,所以length就是9
*/
/*
children属性可以获取的当前元素的所有子元素,但是不包括文本节点,就是只有标签
*/
var lis2 = city.children;
//获取第一个子元素
/*
firstChild属性可以获取到当前元素的第一个子节点(包括空白文本节点)
*/
var firstli = city.firstChild;
/*
firstElementChild属性可以获取到当前元素的第一个子元素(不包括空白文本节点)
但是不支持ie8及以下,
如果需要兼容ie8及以下,则需要判断
*/
var first = city.firstElementChild;
//获取最后一个子元素
/*
lastChild属性可以获取到当前元素的最后一个子节点(包括空白文本节点)
*/
var lastli = city.lastChild;
/*
lastElementChild属性可以获取到当前元素的最后一个子元素(不包括空白文本节点)
但是不支持ie8及以下,
如果需要兼容ie8及以下,则需要判断
*/
var last = city.lastElementChild;
</script>
3、获取父节点和兄弟节点
<body>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
</body>
<script>
//获取当前节点的父节点
var bj = document.getElementById("bj");
var bjParent = bj.parentNode;
//console.log(bjParent);
//获取当前节点的前一个兄弟节点,当然也可能获取到空白的文本
var bjBorther = bj.previousSibling;
//获取前一个兄弟元素,不包括空白的文本,但是ie8以及之前版本不支持
var bjBorther2 = bj.previousElementSibling;
//console.log(bjBorther);
console.log(bjBorther.innerHTML);
//获取当前节点的后一个兄弟节点
</script>
4、querySelect选择器选择元素
//document.querySelect这个方法,只会返回一个值,即使匹配的元素有多个也只会返回一个
//document.querySelectSAll这个方法可以返回多哥符合条件的元素
5、dom的增删改
①增
<!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>
<ul id="city">
<li>成都</li>
<li>北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="add" />
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
//创建一个重庆节点添加到ul下面
//创建li元素节点
/*
该方法用于创建一个元素节点对象,
需要一个标签名作为参数,并将创建好的元素对象返回
*/
var li = document.createElement('li');
//创建广州文本节点
/*
*document.createTextNode
*用来创建一个文本节点对象
需要文本内容作为参数,并将创建好的文本节点对象返回
*/
var cqText = document.createTextNode('重庆');
//将cqText设置为li的子节点
/***
* appendChild
* 将一个节点对象作为子节点添加到父节点中
* 需要一个子节点对象作为参数
* 父节点.appendChild(子节点)
*/
li.appendChild(cqText);
//获取city元素节点
var city = document.getElementById('city');
//将li设置为city的子节点
city.appendChild(li);
}
</script>
</html>
②插入
<!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>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="insert" />
</body>
<script>
//将重庆节点插入到北京前面
var btn = document.getElementById('btn');
btn.onclick = function () {
//创建一个重庆节点添加到ul下面
//创建li元素节点
/*
该方法用于创建一个元素节点对象,
需要一个标签名作为参数,并将创建好的元素对象返回
*/
var li = document.createElement('li');
//创建广州文本节点
var cqText = document.createTextNode('重庆');
//将cqText设置为li的子节点
li.appendChild(cqText);
//获取bj节点
var bj = document.getElementById('bj');
var city = document.getElementById('city');
//将li节点插入到bj节点的前面
/***
* insertBefore可以在指定的子节点面前插入新的子节点
* 语法:父节点.insertBefore(新节点,参照节点)
*
*/
city.insertBefore(li, bj);
}
</script>
</html>
④替换
<!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>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="replace" />
</body>
<script>
//将北京节点替换为重庆节点
var btn = document.getElementById('btn');
btn.onclick = function () {
//创建一个重庆节点添加到ul下面
//创建li元素节点
var li = document.createElement('li');
//创建广州文本节点
var cqText = document.createTextNode('重庆');
//将cqText设置为li的子节点
li.appendChild(cqText);
//获取bj节点
var bj = document.getElementById('bj');
//获取city
var city = document.getElementById('city');
//开始替换
/***
* 可以使用指定的子节点替换已有的子节点
* 语法
* parentNode.replaceChild(newChild,oldChild);
* parentNode:父节点
* newChild:要插入的节点
* oldChild:要替换的节点
*/
city.replaceChild(li, bj);
}
</script>
</html>
⑤删除
<!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>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="erase" />
</body>
<script>
//将北京节点删除
var btn = document.getElementById('btn');
btn.onclick = function () {
//获取bj节点
var bj = document.getElementById('bj');
//获取city节点
var city = document.getElementById('city');
//删除bj节点
/****
* removeChild
* 可以删除一个子节点
* 语法:
* 父节点.removeChild(子节点)
*/
//知道父元素删除子节点
、、city.removeChild(bj);
//不使用父元素删除子节点
bj.parentNode.removeChild(bj);//这个最常用
}
</script>
</html>
⑥关于innerHTML的用法
//读取city里面的html代码
<body>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="read" />
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
var city = document.getElementById('city');
alert(city.innerHTML);
}
</script>
//设置bj节点里面的html代码
<body>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="edit" />
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
var bj = document.getElementById('bj');
bj.innerHTML = '南京';
}
</script>
//使用innerHTML实现添加的操作
<body>
<ul id="city">
<li>成都</li>
<li id="bj">北京</li>
<li>上海</li>
<li>广州</li>
</ul>
<input type="button" id="btn" value="add" />
</body>
<script>
var btn = document.getElementById('btn');
btn.onclick = function () {
var city = document.getElementById('city');
city.innerHTML += "<li>重庆</li>"
}
</script>
四、BOM对象
BOM对象就是浏览器对象,BOM对象比DOM大
1、定时器-延时对象
/*
仅仅只执行一次,代码延时
*/
setTimeout(回调函数,延时的时间(毫秒));
var time = setTimeout(回调函数,等待的毫秒数);
//清除延时函数
clearTimeout(time);
2、location对象
关于location对象它拆分并保存了URL地址的各个组成部分
//常用的方法和属性
属性:
①href:获取完整的URL地址,对其赋值时用于地址的跳转
//例:用户点击跳转,如果不点击,则在 5秒之后跳转,要求里面有秒数倒计时
<!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>
<style>
span {
color: red;
}
</style>
<body>
<a href="http://www.itcast.cn">支付成功<span>5</span>秒钟跳转到首页</a>
</body>
<script>
const a = document.querySelector('a');
let num = 5
let timer = setInterval(function () {
num--;
a.innerHTML = `支付成功<span>${num}</span>秒钟跳转到首页`
if (num === 0) {
clearInterval(timer);
location.href = 'http://www.itcast.cn'
}
}
, 1000);
</script>
</html>
②search属性获取url(网址)中?后面的内容
③hash获取地址(url)中的哈希值,#后面的内容
④reload方法用于刷新当前新页面, 传入true参数时表示强制刷新
3、navigator对象
//该对象记录了浏览器自身的相关信息
常用的属性和方法:
userAgent检测浏览器的版本和平台
例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script>
!(function () {
const userAgent = navigator.userAgent;
//验证是否为Android或iphone
const android = userAgent.match(/(Android);?[\s\/]+([\d.]+)?/);
const iphone = userAgent.match(/(iPhone\sOS)\s([\d_]+)/);
//如果是android或者iphone跳转到至移动站点
if (android || iphone) {
location.href = "http://m.itcast.cn";
}
})();
</script>
</head>
<body>
这是pc端
</body>
</html>
4、history对象
//该对象与浏览器地址栏的操作相对应,如前进、后退、历史记录等
常用的方法或属性:
back():后退功能
forward():前进功能
go(参数):参数1:前进一个页面,-1:后退一个页面
5、本地存储localStorage
本地存储只能存储字符串类型的数据
//存储一个名字 uname:dxy
//用法:localStorage.setItem("键","值");
localStorage("uname","dxy");
//获取数据
//用法:var uname = localStorage.getItem("键");
//删除数据
//用法:localStorage.removeItem("键");
localStorage.removeItem("uname");
本地存储复杂数据类型
<script>
var obj = {
uname: "dxy",
age: 18,
sex: "男"
}
//本地存储复杂数据类型
/***
* 注意:
* 第一个obj是键,第二个才是我们创建的对象值
localStorage.setItem("obj", obj);
* 但是无法直接使用所存的值
*
* 解决方法:
* 需要将复杂数据类型转换为JSON字符串的数据类型
* 语法:JSON.stringify(obj)
*/
//存
localStorage.setItem("obj", JSON.stringify(obj));
//取
//把JSON字符串转换为对象
JSON.parse(localStorage.getItem("obj"));
</script>
五、javascript进阶
1、垃圾回收机制
-
关于全局变量的话,一般不会回收(在关闭页面的时候进行回收)
-
一般情况下局部变量的值,不用了,会被自动回收掉
-
内存泄漏:程序中分配的内存由于某种原因未被释放获取无法释放
2、闭包
概念:一个函数对周围状态的引用捆绑在一起,内层函数中访问到其外层函数的作用域
简单理解:闭包=内层函数+外层函数的变量
简单的Demo理解:
function outer(){
const a=1;
function f(){
console.log(a);
}
f();
}
outer();
常见的Demo形式:(外部可以访问使用 函数内部的变量)
function outer(){
const a=1;
function f(){
console.log(a);
}
return f;
}
const fun = oute();
fun();
闭包的应用:实现数据的私有
function fn() {
let count = 0
function fun() {
count++;
console.log(`函数被调用${count}次`)
}
return fun;
}
const ret = fn();
ret();
//这个count不会被回收
3、箭头函数
语法:
const fn = () =>{函数体}
fn();
//只有一个形参的时候:可以省略小括号
const fn = x =>{
console.log(x);
}
fn(1);
//只有一个形参的时候:还可以省略大括号
const fn = x => console.log(x);
fn(1);
//只有一个形参的时候,如果有返回值,可以省略return
const fn = x =>x+x
console.log(fn(1));
//箭头函数可以直接返回一个对象
const fn = (uname) => ({uname:uname})//第一个参数是属性名,第二个是属性值
console.log(fn("刘德华"));
//箭头函数没有arguments参数,但是有剩余参数
const getSum = (...arr) => {
let sum = 0;
for(let i;i<arr.length;i++){
sum+=arr[i];
}
return sum;
}
getSum(2,3);
//箭头函数的this指向的是上一层的this
<script>
const fn = () => {
console.log(this);//window,并不是箭头函数里面的this,而是上一层,就是script标签里面的
}
fn();
</script>
//对象方法箭头函数 this
<script>
const obj = {
uname:"dxy",
sayHi:() => {
console.log(this);//这个this就是obj
}
}
obj.sayHi();
</script>
const obj = {
uname:"dxy",
sayHi:function () {
console.log(this)
let i = 10;
const count = () => {
console.log(this)//这个this就是obj
}
count();
}
}
obj.sayHi();
4、变量提升
在代码加载前,把变量声明提前,但是不会赋值
<script>
//变量提升,但是只会提升到当前作用域,比如在函数里面,就只会提升到函数作用域
//相当于 var name;但是不赋值
console.log("我是" + name);
var name = "小明";//结果就是我是undefined
</script>
5、动态参数
<script>
//动态参数
function fun() {
let sum = 0;
for (var i = 0; i < arguments.length; i++) {
sum += arguments[i];
}
console.log(sum);
}
fun(2, 3);
</script>
6、剩余数组
<script>
//剩余参数
function fun(a, b, ...arr) {
let sum = 0;
for (let i = 0; i < arr.length; i++) {
//arr中就是6和7
sum += arr[i];
}
sum += a + b;
console.log(sum);
}
fun(2, 3, 6, 7);//18
</script>
7、数组解构
<script>
//第一种
let a = 1
let b = 2
//数组开头的前面必须加分号
;[a, b] = [b, a];
console.log(a, b)
//第二种
const [max, min, mid] = [100, 20, 50]
console.log(max, min, mid)//100 20 50
</script>
8、对象解构
<script>
//对象解构
const { uname, age, sex } = { uname: "张三", age: 18, sex: "男" }
/*等价于
const uname = "张三"
const age = 18
const sex = "男"
*/
console.log(uname, age, sex)
</script>
注意:
- 必须保证属性名和变量名一致
- 变量名可以重新命名,格式:旧属性名:新变量名
const {uname:username,age,sex} = {uname: "张三", age: 18, sex: "男"}
①解构数组对象
<script>
const [{ uname, age }] = [{
uname: "佩奇",
age: 6
}]
console.log(uname, age);
</script>
②多级对象解构
<script>
const pig = {
name: '佩奇',
family: {
mother: '米老鼠',
father: '小红帽'
},
age: 6
}
const { name, family: { mother, father }, age } = pig
console.log(name, mother, father, age)
</script>
9、遍历数组元素(foreach)
<script>
const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
arr.forEach(function (item, index) {
//item是数组元素
//index是数组元素的索引
console.log(item, index);
})
</script>
10、构造函数
<script>
//这样子就不用每次都写很多代码,可以直接封装成一个函数,new 对象时进行调用
function Pig(name, age) {
this.name = name;
this.age = age;
}
const pig1 = new Pig('小猪1', 3);
const pig2 = new Pig('小猪2', 5);
console.log(pig1, pig2);
</script>
11、原型对象
<script>
function Person(name,age){
this.name = name
this.age = age
}
//原型就相当于是一个对象,
/*
原型的作用:
①共享两个对象中相同的方法
②可以把不变的方法,直接定义在prototype对象上面
注意:
在使用原型的时候,将属性就写在构造函数中,
而不变的方法就可以使用原型,这样就不用开辟新的地址了
*/
//原型的使用
/*
注意:原型对象中的this还是指向的是实例化对象
所以在构造函数和原型对象中,this都指向实例化对象
*/
Person.prototype.sayHi = function(){
alert("hi")
}
const p1 = new Person("张三",18)
p1.sayHi()
</script>
①使用原型 对数组扩展方法:求和和求最大值、最小值
script>
//最大值
Array.prototype.max=function(){
//展开运算符
return Math.max(...this)
//原型对象中的this指向实例化对象
}
//最小值
Array.prototype.min=function(){
//展开运算符
return Math.min(...this)
//原型对象中的this指向实例化对象
}
//求和
Array.prototype.sum=function(){
//箭头函数:一个以上的参数,就必须带小括号,只有一句代码,可以不用写大括号
return this.reduce((prev,item)=>prev+item,0)
}
alert([1,2,3,4].min())
alert([1,2,3,4].max())
alert([1,2,3,4].sum())
</script>
12、原型对象中的constructor属性
<script>
/*
constructor属性是原型对象里面的属性
作用:该属性指向该原型对象的构造函数
function Person(){
}
Person.prototype.constructor===Person//是true
*/
function Star(){
}
Star.prototype={
//这样就是直接赋值,就会覆盖掉之前的原本的属性、函数等,
//所以要使用constructor属性让他找到自己的父亲
//加上这行代码
constructor:Star,//重新指回创造这个原型对象的构造函数
sing:function(){
console.log("sing")
},
dance:function(){
console.log("dance")
}
}
</script>
13、对象原型
在这里插入图片描述
对象都会有一个属性__proto__(两个下划线)指向构造函数的prototype原型对象,使得我们对象才可以使用构造函数prototype原型对象的属性和方法
注意:
- __proto__不是js的标准属性
- [[prototype]]和__proto__意义相同
- __proto__用来表明当前的实例对象指向哪个原型对象prototype
- __proto__对象原型里面也有一个constructor属性,指向创建该实例对象的构造函数
在这里插入图片描述
14、原型继承
<script>
function Person() {
this.eyes = 2;
this.head = 1;
}
function Woman() {
}
//让woman继承person
Woman.prototype = new Person();
//再指回原来的构造函数
Woman.prototype.constructor = Woman;
const woman = new Woman();
console.log(woman.eyes);
</script>
15、原型链
查找规则:
- ①当访问对象的属性时,先找该对象是否有这个属性
- ②如果没有就查找它的原型(就是__proto__指向的prototype原型对象)
- ③如果还没有就找原型对象的原型(Object的原型对象)
- ④以此类推直到找到Ojbect为止
- ⑤__proto__对象原型的意义就在于为对象成员机制提供一个方向,或者说一条路线
- ⑥可以使用instanceof运算符用于检查构造函数的prototype属性是否出现在某个实例对象的原型链上面
16、深浅拷贝
(1)浅拷贝
有两种方法
<script>
const obj = {
name: '张三',
age: 18
}
//第一种使用展开运算符
const o1 = { ...obj };
console.log(o);
//第二种使用Object.assign()
const o2 = {};
Object.assign(o2, obj);
console.log(o2);
</script>
注意:浅拷贝在拷贝对象的时候,只能把对象里面单层的属性或方法拷贝,如果该对象中,还有对象,就实现不了拷贝的功能
(2)深拷贝
-
深拷贝通过使用函数递归的方式实现
-
使用lodash库方法
-
<script src="https://cdn.bootcdn.net/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script> <script> const obj = { name: '张三', age: 18, family: { dad: "李四" } } //使用lodash库的cloneDeep方法深拷贝对象 const newObj = _.cloneDeep(obj); console.log(newObj); // 输出:{ name: '张三', age: 18 } </script>
-
-
使用json实现深拷贝
-
<script> const obj = { name: '张三', age: 18, family: { dad: "李四" } } //使用json的形式实现深拷贝 const obj1 = JSON.parse(JSON.stringify(obj)); console.log(obj1); </script>
-
17、异常处理
(1)抛出异常
使用throw关键字,会终止程序,经常和error一起使用
-
<script> function func(x, y) { if (!x || !y) { throw new Error('x和y不能为空'); } return x + y; } console.log(func()); </script>
(2)try/cathch捕获异常
<script>
function func() {
try {
const p = document.querySelector(".p");
p.style.color = "red";
} catch (error) {
//拦截错误,不会中断程序的执行,提示浏览器提供的错误信息
console.log(error.message)
return
} finally {
//不管代码对不对,程序都会执行
console.log("finally")
}
}
</script>
18、改变this指向
-
使用call方法(了解)
-
使用apply方法(理解)
-
语法:f.apply(thisArg,[argArray])
- thisArg:在fun函数运行时指定的this值
- argArray:传递的值,必须包含在数组里面
- 返回值就是函数的返回值
-
<script> const obj = { name: '123' } function f() { console.log(this); } f(); f.apply(obj); </script>
-
实例:使用Math.max()求数组中的最大值
-
<script> console.log(Math.max.apply(Math, [1, 2, 3])); </script>
-
-
-
使用bind方法(掌握)
-
不会调用函数
-
语法:f.bind(thisArg,arg1,arg2,····)
-
thisArg:在fun函数运行时指定的this值
-
arg1,arg2:传递的参数
-
返回是一个函数,但是这个函数里面的this是被更改过的
-
<script> const obj = { age: 18 } function f() { console.log("ad"); } console.log(f.bind(obj)) </script>
-
-
综上:call和apply在执行时,会调用函数,而且改变this指向,bind方法不会调用函数,并且会改变this指向