带你学习javascript的函数进阶(二)

1 严格模式

1.1 什么是严格模式

JavaScript除了提供正常模式外,还提供了严格模式(strict mode)。ES5的严格模式是采用具有限制性Javascript变体的一种方式。即在严格的条件下运行js代码。
严格模式在IE10以上版本的浏览器中才会被支持,旧版本浏览器会被忽略。
严格模式对正常的javascript语义做了一些更改:

  1. 消除了Javascrip语法的一些不合理、不严谨之处,减少了一些怪异行为。
  2. 消除了代码运行的一些不安全之处,保证代码运行的安全。
  3. 提高编译器效率,增加运行速度。
  4. 禁用了在ECMAScript的未来版本中可能会定义的一些语法,为未来新版本的Javascript做好铺垫。比

如一些保留字:class,enum,export,extends,import,super不能做变量。

1.2 开启严格模式

严格模式可以应用到整个脚本或个别函数中。因此在使用时,我们可以将严格模式分为脚本开启严格模式和
为函数开启严格模式两种情况

  1. 为脚本整个脚本开启严格模式

为整个脚步文件开启严格模式,需要在所有语句之前做一个特定语句"use strict"

<scirpt>
  "use strict"
	console.log("这是最严格模式")
 </scirpt>
  1. 为函数开启严格模式

要给某个函数开启严格模式,需要把"use strict";(或'use strict')声明放在函数体所有语句前。

<script>
 	function fn() {
		'use strict' //下面的代码按照严格模式进行
	} 
 </script>

3.3 严格模式中的变化

严格模式对javascript的语
法和行为,都做了一些改变

  1. 变量规定
  • 在正常模式中,如果一个变量没有声明就赋值,默认的事全局变量。
  • var 命令声明,然后再使用
<script>
  ‘use strict’
	num = 10
	console.log(num)
 </script>

效果如下图
image.png
严禁删除已经声明的变量。

  1. 严格模式下this指向问题
  • 以前在全局作用域函数中的this指向window对象。
  • 严格模式下全局作用域中函数中的this事undefined。
  • 以前构造函数时不加new也可以调用,当普通函数,this指向全局对象。
  • 严格模式下,如果构造函数不加new调用,this会报错。 new实例化的构造函数指向创建的对象实例。
  • 严格模式下,定时器里的this指向还是window.
  • 严格模式下,事件、对象还是指向调用者。
  1. 函数变化
  • 严格模式下函数不能有重名的参数
  • 函数必须声明在顶层,新版本的js会引入“块级作用域”(ES6中已引入)。为了与新版本接轨,不允许在非函数的代码块内声明函数,如在if,for语句中声明函数。

2 高阶函数

高阶函数是对其他函数进行操作的函数,它接收函数作为参数或函数作为返回值输出。

function fn(callback) {
	callback && callback()
}
fn(function(){
	alert('lanfeng')
})
function fn() {
	return function() {
  }
}
fn()

此时fn就是一个高阶函数
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用,最典型的就是作为回调函数

3 闭包

3.1 变量作用域

变量根据作用域的不同分为两种:全局变量和局部变量。

  1. 函数内部可以使用全局变量
  2. 函数外部不可以使用局部变量
  3. 当函数执行完时,本作用域内的局部变量会被销毁。

3.2 什么是闭包

闭包指有权访问另外一个函数作用域中变量的函数。也就是说,一个作用域可以访问另外一个函数内部的局部变量。

//fn 外面的作用域可以访问fn内部的局部变量
function fn() {
	var num = 10
  function fun () {
  	console.log(num) //可以访问num
  }
  return fun
}
var f = fn()
f() //10
//fn 外面的作用域可以访问fn内部的局部变量
function fn() {
	var num = 10
  
  // 返回一个匿名函数
  return function() { 
  	console.log(num) //可以访问num
  }
}
var f = fn()
f() //10

闭包的主要作用: 延伸了变量的作用范围

3.3 闭包案例

  1. 循环注册点击事件
//html
<ul class="nav">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
</ul>
//js
//点击li输出当前li的索引
//利用动态田径属性方式
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  lis.index = i
	lis[i].onclick = function() {
  	console.log(this.index)
  }
}
//利用闭包的方式
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  (function(i) {
  	lis[i].onclick = function() {
  	console.log(i)
  }
  })(i)
	
}
  1. 循环中的setTimeout()
//html
<ul class="nav">
  <li>a</li>
  <li>b</li>
  <li>c</li>
  <li>d</li>
</ul>
//js
//利用闭包
var lis = document.querySelector('.nav').querySelectorAll('li')
for(var i=0 ;i<lis.length; i++) {
  (function(i){
  	setTimeout(function() {
    	console.log(lis[i].innerHTML)
    },3000)
  })(i)
}
  1. 计算打车价格
var car = (function() {
		var start = 13;
    var total = 0;
  return {
    //正常价格
  		price: function(n) {
      	if(n <= 3) {
        	total = start
        } else {
        	total = start + (n-3)* 5
        	}
        return total;
      }, 
    	// 拥堵之后
    	yd: function(flag) {
      	flag? total+ 10 :total
      } 
  	}
	})()
console.log(car.price(5))
console.log(car.yd(true))

3.4 闭包总结

  1. 闭包是什么?

闭包就是一个函数(一个作用域可以访问另外一个函数的局部变量)

  1. 闭包的作用是什么?

延伸变量的作用范围

4 递归

4.1 什么是递归

如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
递归函数的作用和循环效果一样
由于递归很容易发生“栈溢出”(stack overflow),所以必须要加退出条件 return

4.2 利用递归求数学题

  1. 求123...*n
function fn(n) {
  if(n = 1) {
  	return 1
  }
	return n * fn(n-1)
}
console.log(fn(3)) // 6

4.3 利用递归求:根据id返回对应的数据对象

var data = [{
	id:1,
  name:'家电',
  goods: [
    {
      id: 11,
      gname: '冰箱'
    },
    {
    	id: 12,
      gname: '洗衣机'
    }
  ]
},
            {
            id: 2,
              name: '服饰'
            }
 ]
function getObj(arr, id) {
  var o = {}
	arr.forEach(function(item){
  	if(item.id === id) {
    	o= item
    } else if(item.goods && item.goods.length>0) {
    		o =getObj(item.goods, id);
    }
  })
  return o
}
console.log(getObj(data, 1))

5 递归

5.1 浅拷贝和深拷贝

  1. 浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
  2. 深拷贝拷贝多层,每一级别的数据都会拷贝。
  3. Object.assign(target, ...sources) es6新增方法可以浅拷贝
var obj = {
	id: 1,
  name: 'andy',
  msg: {
   age: 18
  }
}
var o = {}
for(var k in obj) {
  // k是属性名
	o[k] = obj[k]
}
console.log(o)
o.msg.age = 20
console.log(obj) //obj发生变化

//用es6语法糖
Object.assign(o, obj)

image.png

//深拷贝,应用递归的方法
function deepCopy(newObj, oldObj) {
	for(var k in oldObj) {
  	//判断我们的属性值属于哪种类型
    var item = oldObj[k]
    // 判断是否是数组
    if(item instanceof Array) {
    	newObj[k] = []
      deepCopy(newObj[k], item)
      
    } else if(item instanceof Object) {
      //判断是否是对象
      newObj[k] = {}
      deepCopy(newObj[k], item)
    } else { // 属于简单数据类型
    	 newObj[k] = item
    }  
    
  }
}
deepCopy(o,obj)
console.log(o)

总结

本篇文章主要分享了函数的严格模式、高阶函数、闭包、递归、深拷贝、浅拷贝等知识点的用法及应用。如果想了解更多,请扫描二维码
qrcode_for_gh_4d3763fa9780_258 (1).jpg

posted @ 2020-03-03 08:45  前端岚枫  阅读(249)  评论(0编辑  收藏  举报