递归:
递归函数是指在函数内部调用函数自身。
注意:
递归的出口:什么情况下结束调用
递归的入口:什么情况下调用自已
//递归实现阶乘
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关键字
- 全局的this
全局的this就是window对象
console.log(window); //Window
console.log(this); //Window
console.log(this === window); //true - 函数中的this
原则:谁调用函数,函数中的this就指向谁
提醒:如果开启了严格模式,this不会指向window对象
function fn(){
console.log('函数中的this:', this); //Window
}
fn(); //因为这里是window在调用fn函数,所以指向window - 对象方法中的this
指向对象本身
var obj={};
obj.name="张三疯";
obj.show=function(){
console.log(this===obj); //true
};
obj.show(); - 构造函数中的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以数组形式传参数
面试题: call()、apply()和bind()的区别:
都能改变this的指向
call()/apply()是立即调用函数
bind():绑定完this后,不会立即调用当前函数,而是将函数返回,因此后面还需要再加()才能调用。
PS:bind()传参的方式和call()一样。
分析:
为什么ES5中要加入bind()方法来改变this的指向呢?因为bind()不会立即调用当前函数。
bind()通常使用在回调函数中,因为回调函数并不会立即调用。如果你希望在回调函数中改变this,不妨使用bind()。
网友评论