1.严格模式
1.1什么是严格模式
严格模式是采用具有限制性JavaScript变体的一种方式,从而使代码隐式地脱离“马虎模式/稀松模式/懒散模式“(sloppy)模式
1.2开启严格模式
严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式分为为脚本开启严格模式和为函数开启严格模式两种情况。
-
情况一 :为脚本开启严格模式
-
有的 script 脚本是严格模式,有的 script 脚本是正常模式,这样不利于文件合并,所以可以将整个脚本文件放在一个立即执行的匿名函数之中。这样独立创建一个作用域而不影响其他 script 脚本文件。
<script> "use strict"; //当前script标签开启了严格模式 </script> <script> //当前script标签未开启严格模式 </script>
-
-
情况二: 为函数开启严格模式
-
要给某个函数开启严格模式,需要把“use strict”; (或 'use strict'; ) 声明放在函数体所有语句之前。
function fn(){ "use strict"; return "123"; } //当前fn函数开启了严格模式
-
1.3严格模式中的变化
严格模式对 Javascript 的语法和行为,都做了一些改变。
'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.高阶函数
高阶函数:,一个函数可以接收另一个函数作为参数,或者是返回一个函数。常见的高阶函数有map、reduce、filter、sort等。
条件其一:
-
参数是函数
-
函数作为返回值
-
// 函数作为参数 function fun(fun) { console.log(fun); // 函数作为返回值 return fun2(10, 20); } function fun2(num1, num2) { return num1 + num2; } var rel = fun(fun2); console.log(rel);//30
3.闭包
内部函数可以访问外部函数的参数和变量 形成的词法环境叫做闭包
var num=100;
function fun(){
var num2=200;
function fun2(){
//因为作用域 才可以查找到num2
console.log(num2);//200
}
fun2();
}
fun();
3.3 闭包的作用
作用:延伸变量的作用范围。
function fn() { var num = 10; function fun() { console.log(num); } return fun; } var f = fn(); f();
总结:
-
闭包有三个特性:
-
函数嵌套函数
-
函数内部访问外部函数的参数或变量
-
可以使函数中的变量可以长期驻扎在内存
-
使用闭包的好处 1.使函数内部变量长期驻扎在内存中 2.避免全局变量的污染(多人定义同样名字的全部变量冲突)
-
使用闭包的坏处: 内存泄漏(应用程序不再用到的内存,由于某些原因,没有及时释放,就叫做内存泄漏。)
3.4 闭包的案例
<div class="content">
<div class="tab">
<div class="active">首页</div>
<div>详情</div>
<div>发现</div>
<div>我的</div>
</div>
<div class="detail">
<div class="active-box">首页内容</div>
<div>详情内容</div>
<div>发现内容</div>
<div>我的内容</div>
</div>
</div>
<script>
var tabs = document.querySelectorAll(".tab div");
var details = document.querySelectorAll(".detail div");
// 排他思想
function slibings(ele){
for(var k=0;k<ele.length;k++){
ele[k].className="";
}
}
// 使用闭包
for (var i = 0; i < tabs.length; i++) {
(function (k) {
// 利用闭包存储变量
tabs[k].onclick = function () {
console.log(k);
slibings(tabs)
tabs[k].className = "active";
slibings(details)
details[k].className = "active-box";
}
})(i)
}
4.递归
4.1什么是递归
递归:让函数在内部自己调用自己
function fun(num) {
num++;
console.log(num);//2 3 4 5 6
if (num == 6) {
return num;//终止代码
} else {
console.log(num);
return fun(num);
}
}
fun(1);
4.2利用递归求1~n的阶乘
//利用递归函数求1~n的阶乘 1 * 2 * 3 * 4 * ..n
function fn(n) {
if (n == 1) { //结束条件
return 1;
}
return n * fn(n - 1);
}
console.log(fn(3));
抚平数组:
// 多维转一维
var arr = [1, 2, 3, [4, 5, 6, [7, 8, 9, [10, 11, 12]]]];
function flatArr(data, relArr) {
relArr = relArr || [];
// console.log(relArr);
// 2.将多维数组进行遍历
data.forEach(function (v) {
// 3.判断当前元素如果是一个数组
if (Array.isArray(v)) {
// 4.利用递归 再次调用自己并将当前数组再次传入函数
flatArr(v, relArr);
} else {
// 5.如果当前元素不是数组 那么将添加到新数组内
relArr.push(v);
}
})
return relArr;
}
// 1.调用函数传入多维数组
var rel = flatArr(arr);
console.log(rel);//(12) [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
5.浅拷贝与深拷贝
浅拷贝 : 赋值出来的对象与源对象共用同一个内存地址,存储在同一块空间 改变其中一个对象另一个也会改变
1.赋值
var obj={
name:"李莉",
age:19,
gender:"女",
hobby:["唱歌","跳舞","画画"]
}
var obj2= {
name: "王宸",
sayHi:function(){
console.log("It's the last day of August");
}
}
// 1.赋值
var obj2=obj;
obj2.hobby[0]="西游记";
console.log(obj);//{name: '李莉', age: 19, gender: '女', hobby: Array(3)}
console.log(obj2);//{name: '李莉', age: 19, gender: '女', hobby: Array(3)}
2.使用for in
var obj={
name:"李莉",
age:19,
gender:"女",
hobby:["唱歌","跳舞","画画"]
}
var obj2= {
name: "王宸",
sayHi:function(){
console.log("It's the last day of August");
}
}
// 2.使用for in
var newobj={}
for(var k in obj){
newobj[k]=obj[k];
}
console.log(obj);//{name: '李莉', age: 19, gender: '女', hobby: Array(3)}
console.log(newobj);
3使用Object.assign
var obj={
name:"李莉",
age:19,
gender:"女",
hobby:["唱歌","跳舞","画画"]
}
var obj2= {
name: "王宸",
sayHi:function(){
console.log("It's the last day of August");
}
}
var newobj={};
Object.assign(newobj,obj,obj2);
console.log(newobj);
5.2 深拷贝
深拷贝:重新开辟一块空间用来存储新对象 与源对象不共用一块内存空间
5.2.1 递归深复制对象
// 封装函数
function deepCopy(newobj, oldobj) {
for (var k in oldobj) {
// 判断我们的属性值属于那种数据类型
// 1. 获取属性值 oldobj[k]
var item = oldobj[k];
// 2. 判断这个值是否是数组
if (item instanceof Array) {
newobj[k] = [];
deepCopy(newobj[k], item)
} else if (item instanceof Object) {
// 3. 判断这个值是否是对象
newobj[k] = {};
deepCopy(newobj[k], item)
} else {
// 4. 属于简单数据类型
newobj[k] = item;
}
}
};
5.2.2 使用JSON
方法
// 使用JSON下面的两个方法
// JSON.stringify()将对象转换为json字符串格式
// JSON.parse() 将字符串转换为json对象格式
// console.log(JSON.parse(JSON.stringify(obj)));