1.严格模式 'use strict'
JavaScript 除了提供正常模式外,还提供了严格模式(strict mode)。ES5 的严格模式是采用具有限制性 JavaScript变体的一种方式,即在严格的条件下运行 JS 代码。
严格模式在 IE10 以上版本的浏览器中才会被支持,旧版本浏览器中会被忽略。
设立严格模式的原因:
1、消除Javascript语法的一些不合理、不严谨之处,减少一些怪异行为;
2、消除代码运行的一些不安全之处,保证代码运行的安全;
3、提高编译器效率,增加运行速度;
4、为未来新版本的Javascript做好铺垫。
1.2严格模式下的语法变化:
'use strict'
num = 10
console.log(num)//严格模式后使用未声明的变量
--------------------------------------------------------------------------------
var num2 = 1;
delete num2;//严格模式不允许删除变量
--------------------------------------------------------------------------------
function fn() {
console.log(this); // 严格模式下全局作用域中函数中的 this 是 undefined
}
fn();
---------------------------------------------------------------------------------
function Person() {
this.sex = '男';
}
// Person();严格模式下,如果 构造函数不加new调用, this 指向的是undefined 如果给他赋值则 会报错.
var p1 = new Person();
console.log(p1.sex);
----------------------------------------------------------------------------------
setTimeout(function() {
console.log(this); //严格模式下,定时器 this 还是指向 window
}, 2000);
----------------------------------------------------------------------------------
// 严格模式下,函数里的参数不允许重名
function fun1(num, num) {
console.log(num + num);
};
fun1(2, 3);
2.高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
只需满足以下任意一个条件,即是高阶函数:
1. 接受一个或多个函数作为输入
2. return 返回另外一个函数
// 高阶函数
// 函数作为参数
function fun(fun) {
console.log(fun);
// 函数作为返回值
return fun2(10,20);
}
function fun2(num1, num2) {
return num1 + num2;
}
var rel = fun(fun2);
console.log(rel);
3.闭包
概念:内部函数访问其所在的外部函数中声明的参数和变量,形成的词法环境叫闭包.
闭包有三个特性:
- 1、函数嵌套函数
- 2、函数内部访问外部函数的参数或变量
- 3、可以使函数中的变量可以长期驻扎在内存
使用闭包的好处:
- 1、变量长期驻扎在内存中
- 2、避免全局变量的污染(多人定义同样名字的全部变量冲突)
- 3、私有成员的存在
使用闭包的坏处:
- 1、常驻内存
- 2、会增大内存的使用量
- 3、使用不当会造成内存泄露
注意:内存泄露:指的是应用程序不再用到的内存,由于某些原因,没有及时释放,就叫做内存泄漏。
会造成内存泄漏的js操作:
1.意外的全局变量
2.未清理的DOM元素的引用
3.被遗忘的定时器或者回调函数
4.闭包
5.过多的console.log语句
var num = 100;
function fun(a) {
var num = 200;
function fun2() {
//作用域链
console.log(a);
console.log(num);
}
fun2();
}
fun(123)
3.1 闭包排他案例(自执行函数)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
.content {
width: 800px;
height: 800px;
border: 1px solid red;
margin: 100px auto;
}
.content .tab {
width: 100%;
height: 50px;
display: flex;
border-bottom: 1px solid skyblue;
}
.content .tab div {
flex: 1;
height: 50px;
text-align: center;
line-height: 50px;
border-right: 1px solid skyblue;
}
.content .tab div:last-child {
border-right: 0px;
}
.active {
color: red;
}
</style>
</head>
<body>
<div class="content">
<div class="tab">
<div class="active">首页</div>
<div>详情</div>
<div>发现</div>
<div>我的</div>
</div>
</div>
<script>
var tabs = document.querySelectorAll(".tab div");
function slibings(ele) {
for (var i = 0; i < ele.length; i++) {
ele[i].className = "";
}
}
// tabs.forEach()
for (var i = 0; i < tabs.length; i++) {
(function (k) {
// 利用闭包存储变量
tabs[k].onclick = function () {
console.log(k);
slibings(tabs)
tabs[k].className = "active";
}
})(i)
}
</script>
</body>
</html>
4.递归
递归:让函数在内部自己调用自己
//递归求阶乘
function sum(num) {
// console.log(num - 1);
if (num == 1) {
return 1;
} else {
// 13 * sum(12)
return num * sum(num - 1);
}
}
var rel = sum(4);
console.log(rel);
4.1抚平函数(多维转一维)
运用的结束闭包的形式来写的
// 多维转移为一维数组
var arr =[1,2,3,4,[5,6,7,[8,9,10,[11,12,13]]]];
var relArr=[]
function flatArr(date,){
// 2、将多维数组进行遍历
date.forEach(function(v){
//3、判断当前元素如果是一个数组
if(Array.isArray(v)){
console.log()
flatArr(v);
// 4、 利用递归 再次调用自己并将当前数组再次传入函数
// console.log(flatArr(v))
}else{
// 5、如果当前元素不是数组 那么将添加到新数组内
relArr.push(v);
}
})
return relArr;
}
//1、 调用函数传入多维数组
var rel1=flatArr(arr);
console.log(rel1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
// 方法二:更减少类存的占用
// 定义一个全局变量也还要删除
// 局部变量在函数内随着函数的创建而产生,函数消失该局部变量也消失
var arr1 =[1,2,3,4,[5,6,7,[8,9,10,[11,12,13]]]];
function flatArr(date,relArr){
console.log(relArr);
relArr=relArr||[];
date.forEach(function(v){
if(Array.isArray(v)){
console.log()
flatArr(v,relArr);
// console.log(flatArr(v))
}else{
relArr.push(v);
}
})
return relArr;
}
// 调用
var rel1=flatArr(arr1);
console.log(rel1) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
5.Object.assign()与深拷贝浅拷贝
5.1 Object.assign()实现浅拷贝
拷贝出来的目标对象的地址和源对象的地址的内存空间是同一块空间
让几个对象共用一个内存
浅拷贝的缺点当该另一个对象的属性原对象属性也会被修改(公用一个地址)
1.赋值
var obj = {
name: "熊大",
age: 20,
gender: "🚹",
hobby: ["三国", "云边有个小卖部", "骆驼祥子"]
}
var obj2 = {
name: "化晨",
sayHi: function () {
console.log("to day is 八月 last day");
}
}
1.赋值
var obj2 = obj;
2.使用for in
var newobj = {}
for (var k in obj) {
newobj[k] = obj[k];
}
console.log(obj);
console.log(newobj);
//for..in中是通过[]来调用
3.使用Object.assign(target, ...sources)
Object.assign()方法用于将所有可枚举属性的值从一个或多个源对象分配到目标对象。它将返回目标对象。
参数: target:目标对象。sources:源对象。
返回值:返回目标对象。
var newobj = {};
// Object.assign(target,sources)
Object.assign(newobj, obj, obj2);
console.log(newobj);
5.2 深拷贝
克隆出一个对象,数据相同
但是引用地址不同
方法一 .使用JSON下面的两个方法
JSON.stringify()将对象转换为json字符串格式
JSON.parse() 将字符串转换为json对象格式
var obj3 = JSON.parse(JSON.stringify(obj));
obj.hobby[0] = "红楼梦"
console.log(obj3);
先转化为字符串在转化为对象就会建立一个新的对象不同的地址,修改不会改变原对象
方法二:通过递归深刻复制对象
var obj = {
name: "熊大",
age: 20,
gender: "🚹",
hobby: ["三国", "云边有个小卖部", "骆驼祥子", {
lookmovies: ["林正英", "漫威", "贞子", "釜山行", "生化危机"]
}]
}
var newobj = {}
// 1.递归:在函数内部自己调用自己
function deepCopy(newobj, obj) {
for (var k in obj) {
// k 属性
// obj[k] 属性值
// 先获取属性值
var value = obj[k];
if (value instanceof Array) {
console.log(value);
console.log(k);
newobj[k] = [];
deepCopy(newobj[k], value)
} else if (value instanceof Object) {
newobj[k] = {};
deepCopy(newobj[k], value)
} else {
newobj[k] = value;
}
}
return newobj
}
deepCopy(newobj, obj);
obj.hobby[0] = "西游记";
obj.hobby[3].lookmovies[1] = "葫芦娃"
console.log(newobj);
console.log(obj)