单信js——4难点部分

138 阅读5分钟

###递归: 递归函数是指在函数内部调用函数自身。 注意: 递归的出口:什么情况下结束调用 递归的入口:什么情况下调用自已

//递归实现阶乘 var fn=function(n){ if(n==1){ return 1; //递归的出口 } return n*arguments.callee(n-1); //在函数内部可以使用 arguments.callee调用函数自身 }

var result=fn(5); //54321 console.log(result);

###函数的惰性载入 是用来减少每次代码执行时的重复性的分支判断,通过对对象的重新定义来屏蔽原来对象的分支判断。 惰性方式相对于初次加载立即执行,可以在需要时来初始化,避免页面初次加载就执行而消耗性能。实现让机器在执行时,也学会了去改进自己的代码了

####匿名函数 就是指没有名称的函数。 匿名函数可以赋给一个变量,也可以直接执行。 如果只需要执行一次,就不需要赋给变量 如果需要多次调用执行,就赋给变量,用变量多次调用 匿名函数出现的目的就只有两个: 打包一段需要立即执行的程序逻辑。 缩小函数内部成员作用域,同时函数本身也会在执行完毕后,脱离引用被回收,减少全局污染。

###第二天回顾

1. JSON
	1) 什么是JSON?
		JSON是一种轻量级的数据交换格式,天然就是JS对象
		
	2) JSON的格式
		{"键名":值, "键名":值}
		
		获取JSON数据的原则:
			看到大括号就是对象:  obj.name  obj['name']
			看到中括号就是数组: arr[0]
			
	3) JSON的转换
		//JSON格式的字符串转换成对象
		var obj=JSON.parse(字符串);
		
		//将对象转换成字符串
		var str=JSON.stringify(对象);
		
2. 作用域
	1) 什么是作用域?
		作用域是指函数的封装特性产生独立的运行(上下文)环境,运行环境就可以将变量或函数划分为不同的作用域。
		
	2) 作用域的划分
		a. 全局作用域
			函数外定义的数据都是全局作用域,在任意地方都能被访问
			
		b. 局部作用域
			函数内定义的数据都是局部作用域,只能在当前函数内被访问
			
		c. 块级作用域
			ES5以前没有块级作用域的概念, 可以使用IIFE实现块级作用域
			ES6以后就有了块级作用域,可以使用 let关键词实现
			
	3) 作用域链
		正常情况下,函数内可以访问上一级函数的数据,上一级函数可以再访问上一级作用域的数据,
这就形成了作用域链条,可以实现最里的语句访问最顶层的数据。

3. IIFE
	1) 什么是IIFE?
		IIFE就是【立即执行   函数表达式】,相当于块级作用域,将一段代码封装函数加载时立即执行,执行完以后立即销毁,不会有任何遗留。
		
	2) IIFE的写法
		(function(){
			...代码段...
		})();
		
		false || function(){
		}();

4. 闭包
	1) 什么是闭包?
		闭包是一种作用域的体现,体现正常情况下函数外不能访问函数内的数据,函数内可以访问函数外的数据。
		闭包是一种特殊写法,将函数内的子函数暴露在全局上,子函数可以被全局调用,又可以访问到上一级函数的数据。
		实现函数外的语句可以函数内的数据。
		
	2) 闭包的作用?
		函数外访问函数内的数据。
		封装插件、封装功能模块...
		
	3) 闭包的写法
		(function(){
			var i=0;
			function _show(){
				....
			}
			
			window.show=_show;
		})();
		
		(function(){
			var i=0;
			window.show=function(){
				return i++;
			}
		})();
		
		var show=(function(){
			var i=0;
			return function(){
				return i++;
			}
		})();

this关键字

  1. 全局的this 全局的this就是window对象 console.log(window); //Window console.log(this); //Window console.log(this === window); //true
  2. 函数中的this 原则:谁调用函数,函数中的this就指向谁 提醒:如果开启了严格模式,this不会指向window对象 function fn(){ console.log('函数中的this:', this); //Window } fn(); //因为这里是window在调用fn函数,所以指向window
  3. 对象方法中的this 指向对象本身 var obj={}; obj.name="张三疯"; obj.show=function(){ console.log(this===obj); //true }; obj.show();
  4. 构造函数中的this 指向new创建的实例 function Person(name,age){ this.name=name; this.age=age; console.log(this); } var p1=new Person('李四爷',88); //Person {name: "李四爷", age: 88} var p2=new Person('王小五',18); //Person {name: "王小五", age: 18}

###借来的this: 所有的函数都拥有三个方法,可以实现将函数中的this指向新对象(修改函数中this的指向):

  • call 主动式将函数中的this指向新对象,调用一次立即执行一次 语法: 函数.call(对象, 参数1, 参数n);

  • apply 效果同上 语法:函数.call(对象, [参数1,参数2,参数n]);

  • bind : 被动式的改变this的指向 语法: 回调函数.bind(对象,参数1,参数2);

下面例子,使用call或者 apply方法修改this的指向
var p1={"name":"周瑜"};
p1.phone=function(){
console.log(this.name + '给小乔打1个小时电话');
}
p1.phone(); //周瑜给小乔打1个小时电话


var p2={"name":"曹操"};
p1.phone.apply(p2);  //曹操给小乔打1个小时电话

var p1={"name":"周瑜"};
p1.phone=function(target,time){
console.log(this.name + '给'+target+'打'+time+'电话');
}
p1.phone('小乔','10个小时');   //周瑜给小乔打10个小时电话

var p2={"name":"曹操"};
p1.phone.apply(p2,['刘备','1分钟']); //在调用方法时还可以传参数
//曹操给刘备打1分钟电话

call apply bind的区别:

  • 相同点: 都是函数的原型方法,可以改变函数中this的指向 第一个参数都写要将this修改到的目标 都可以传递参数

  • 不同点: call apply是主动式的,修改this指向时立即调用一次 bind是被动式的,只修改this的指向,不执行 call的参数直接列举在对象后面,apply以数组形式传参数