函数
函数的定义和调用
函数的定义方式
- 函数声明方式function关键字(命名函数)
- 函数表达式(匿名函数)
- new Function()
var fn = new Function('参数1','参数2',......,'函数体')
- Function里面参数都必须是字符串格式
- 第三种方式执行效率低,也不方便书写,因此较少使用
- 第三种方式执行效率低,也不方便书写,因此较少使用
- 函数也属于对象
函数的调用方式
- 普通函数
- 对象的方法
- 构造函数
- 绑定事件函数
- 定时器函数
- 立即执行函数
函数内的this指向
这些this的指向,是当我们调用函数的时候确定的。调用方式的不同决定了this的指向不同this一般指向我们的调用者。
调用方式 | this指向 |
---|---|
普通函数第调用 | window |
构造函数调用 | 实例对象 原型对象里面的方法也指向实例对象 |
对象方法调用 | 该方法所属对象 |
事件绑定方法 | 绑定事件对象 |
定时器函数 | window |
立即执行函数 | window |
改变函数内部的this指向
javascript为我们提供了一些函数方法来帮我们更优雅的处理函数内部this指向的问题,常用的有bind() call() apply()三种方法。
- call()方法
call方法可以用来调用函数、改变函数内部的this指向、向函数传递参数。
fun.call(thisArg,a,b)
- thisArg:在函数运行时指定的this值
- a,b:传递的参数值
- apply()方法
apply()方法调用一个函数,简单理解为调用函数的方式,但是他可以改变函数的this指向。
fun.apply(thisArg,[arr])
示例代码:
//apply()方法改变函数的this指向
var o={
name:'张三'
}
function Fn(arr){
console.log(arr);
console.log(this);
}
Fn.apply(o,['red']);
//求最大值
var arr1=[9,5,7,55,33,77,99];
var max=Math.max.apply(Math,arr1);
var min=Math.min.apply(Math,arr1);
console.log(max,min);
- bind()方法
bind()方法不会调用函数,但是能改变函数内部的this指向。
fun.bind(thisArg,arg,arg,.......)
- thisArg:在fun函数运行时指定的this值
- arg1,arg2:传递的其它参数
- 返回由指定的this值和初始化参数改造的原函数拷贝
- 返回的是原函数改变this之后产生的新函数
示例代码:
//bind()方法
var x={
name:'张雨生',
age:20,
xn:'男'
}
function fn(a,b){
console.log(this);
console.log(a+b);
}
var f=fn.bind(x,5,6);//不会调用原函数
f();
高阶函数
function fn(c) {
c && c();
}
function cb() {
alert('你好');
}
函数也是一种数据类型,同样可以作为参数,传递给另外一个参数使用,最典型的就是作为回调函数。
function fn() {
return function() {}
}
fn();
此时fn就是一个高阶函数。
闭包
变量作用域
变量根据作用域不同分为两种:全局变量和局部变量。
- 函数内部可以使用全局变量
- 函数外部不可以使用局部变量
- 当函数执行完毕,本作用域内的局部变量会销毁
什么是闭包
闭包是指有权访问另一个函数作用域中的变量的函数,简单理解就是,一个作用域可以访问另一个函数内部的局部变量。
闭包的作用: 延伸了变量的作用范围。
示例代码:
//闭包(内部函数访问外部函数的局部变量)
function fn1(){
var num=10;
function fn2(){
console.log(num);
}
fn2();
}
fn1();
代码示例2:
//闭包(内部函数访问外部函数的局部变量)
function fn1(){
var num=10;
function fn2(){
console.log(num);
}
fn2();
}
fn1();
//这是简写
function num(){
var num=10;
return function(){
//返回值可以实现全局作用域访问局部作用域里面的变量就相当于return赋值给f然后f调用同时它也叫高阶函数。
console.log(num);
}
}
var f=num();
f();
闭包案例:
//闭包案例
//原来的写法
var list=document.querySelector('ul').querySelectorAll('li');
for(var i=0;i<list.length;i++){
list[i].index=i;
list[i].onclick=function(){
console.log(this.index);
}
}
//用闭包实现点击当前小li获取当前的索引号
for(var i=0;i<list.length;i++){
(function(i){
list[i].onclick=function(){
console.log(i);
}
})(i);
}
//闭包定时器案例
for(var i=0;i<list.length;i++){
(function(n){
setTimeout(function(){
console.log(list[n].innerHTML);
},3000);
})(i);
}
// 用闭包求打车价格
let car=(function() {
let start = 13; //起步价
let total = 0; //总价
return{
price:function(n){
if(n<=3){
total=start;
}else{
total=start+(n-3)*5;
}
return total;
},
wall:function(flag){
return flag ? total+10 : total;
}
}
})();
let result=car.price(5);
let wal=car.wall(true);
console.log(result);
console.log(wal);
递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。简单理解:函数内部自己调用自己这个函数就是递归函数,递归函数的作用和循环效果一样。 由于递归很容易发生”栈溢出”错误,所以必须要加退出条件 return。
代码示例:
//递归案例求1~n的阶乘
function f1(n){
if(n==1){
return 1;
}
return n*f1(n-1);
}
var result=f1(3);
console.log(result);
3*fn(3-1) 2
2*fn(2-1) 1
3*1
3*2
6
代码示例2:
//利用递归求斐波那契数列 1,1,2,3,5,8,13,21......
//用户输入一个数字n就可以求出这个数字对应的数列值。
function series(n) {
if (n == 1 || n == 2) {
return 1;
}
return series(n - 1) + series(n - 2);
}
let result = series(3);
console.log(result);
代码示例3:
// 利用递归遍历数据
var data = [{
id: 1,
name: '家电',
gods: [{
id: 11,
name: '电视'
},
{
id: 12,
name: '洗衣机'
}
]
},
{
id: 2,
name: '服饰'
}
];
function getdata(json, id) {
let o={}
json.forEach(function(value) {
if (value.id == id) {
o=value;
return value;
} else if (value.gods && value.gods.length != 0) {
o=getdata(value.gods, id);
}
});
return o;
}
let result = getdata(data, 11);
console.log(result);
浅拷贝和深拷贝
- 浅拷贝:浅拷贝只是拷贝一层,更深层次对象级别的只拷贝引用。
- 浅拷贝在拷贝复杂类型的时候拷贝的是复杂类型的地址,如果修改了拷贝过来的对象或者是数组的里面的数据那么原拷贝对象里面的数据也会被修改。
- 深拷贝:深拷贝拷贝多层,每一层的数据都会拷贝。
- 深拷贝在拷贝的对象或者数组等复杂类型时,他会在内存开辟一个空间单独存放拷贝过来的复杂类型,如果修改了拷贝过来的对象里面的数据原拷贝对象不会被影响(修改)。
浅拷贝方法:Object.assign(target,source)第一个参数是拷贝给谁(新对象),第二个参数是旧对象对象。
代码示例:
//实现浅拷贝
var obj={
name:'张三',
age:18,
msg:{
xin_bie:'男'
}
};
var o={};
// for(var k in obj){
// o[k]=obj[k]
// }
Object.assign(o,obj);
o.msg='女';
console.log(o);
代码实例2:
//递归实现深拷贝
var obj={
name:'刘德华',
age:18,
msg:{
sex:'男'
},
color:['red','blue']
};
var o={};
function copy(newobj,bj){
for(var k in bj){
var item=bj[k];//旧
if(item instanceof Array){
newobj[k]=[];
copy(newobj[k],item);
}else if(item instanceof Object){
newobj[k]={};
copy(newobj[k],item);
}else{
newobj[k]=item;
}
}
}
copy(o,obj);
console.log(o);