第二十二节:Javascript 高级
this指向
这些 this 的指向,是当我们调用函数的时候确定的。调用方式的不同决定了this 的指向不同,一般指向我们的调用者
- 全局作用域或者普通函数中this指向全局对象window(注意定时器里面的this指向window)
- 方法调用中,谁调用 this就指向谁
- 构造函数中 this指向构造函数的实例
call 方法
作用:
- 调用函数
- 更改函数体中的this指向
- call 的继承性
/ 语法格式:
函数名.call(对象, 实参1, 实参2... 实参n);
let str = { name: '张学友' };
let star = { name: '刘德华' };
function fn (a, b, c) {
console.log(this);
console.log(a + b + c);
};
fn.call(star, 10, 20, 30); // this是star,60
call 应用场景:经常做继承
function Father (name, age) {
this.uname = name;
this,age = age;
// this ==> window
};
function Son (name, age) {
// this ==> window
// call 将Father中的this指向Son
Father.call(this, uname, age);
};
let son = new Son('张三', 18);
console.log(son); // Son {uname: "张三"}
apply 方法
作用:
- 立刻调用函数
- 更改函数体中的this指向
- 参数以数组形式存放
apply 应用场景:经常跟数组有关系
let arr = [10, 20, 30, 40, 50];
console.log(Math.max(10, 20, 30, 40, 50));
console.log(Math.max.apply(Array, arr));
bind 方法
作用:
- 更改this指向
特点:
- 不会立刻调用函数,会返回一个新函数
- 能改变函数内部this 指向,返回的是原函数改变this之后产生的新函数
如果只是想改变 this 指向,并且不想调用这个函数的时候,可以使用bind
/ 语法格式:
函数名.bind(对象)
bind 应用场景:不调用函数,但是还想改变this指向
严格模式
严格模式对正常的 JavaScript 语义做了一些更改:
- 消除了 Javascript 语法的一些不合理、不严谨之处,减少了一些怪异行为。
- 消除代码运行的一些不安全之处,保证代码运行的安全。
- 提高编译器效率,增加运行速度。
- 禁用了在 ECMAScript 的未来版本中可能会定义的一些语法,为未来新版本的 Javascript 做好铺垫。比如一些保留字如:class,enum,export, extends, import, super 不能做变量名
// 1. 开启全局作用域下的严格模式
'use strict'
// 2. 开启局部作用域下的严格模式
function fn () {
// 为函数开启严格模式
'use strict'
};
(function () {
// 为脚本开启严格模式
'use strict'
});
开启严格模式的变化
function fn () {
'use strict';
console.log(this); // this不会指向window,而是指向 undefined
};
高阶函数
高阶函数:函数的参数是函数 或者 函数的返回值是函数
高阶函数是对其他函数进行操作的函数,它接收函数作为参数或将函数作为返回值输出
Array 方法
map()
遍历源数据,返回修改过的数据
let arr = [10, 20, 30, 40];
arr.map(function (item, index, arr) {
return console.log(item);
});
// 结果为:10, 20, 30, 40
item:必须。当前元素
index:可选。当前元素索引值
arr:可选。整个数组
every()
判断每一项是否都满足条件,都满足返回 true,有一项不满足就返回 false
let arr = [10, 20, 30, 40];
arr.every(function(item, index, arr) {
return item > 70;
});
// 结果为:false
item:必须。当前元素
index:可选。当前元素索引值
arr:可选。整个数组
some()
判断每一项是否都满足条件,只要有一项满足就返回 true,都不满足就返回 false
let arr = [10, 20, 30, 40];
arr.some(function(item, index, arr) {
return item > 35;
});
// 结果为:true
item:必须。当前元素
index:可选。当前元素索引值
arr:可选。整个数组
filter()
创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素。
注意:
filter() 不会对空数组进行检测。
filter() 不会改变原始数组。
let arr = [10, 20, 30, 40];
arr.some(function(item, index, arr) {
return item > 25;
});
// 结果为:
item:必须。当前元素
index:可选。当前元素索引值
arr:可选。整个数组
sort()
对数组元素进行排序
item1 - item2 是从小到大排序
item2 - item1 是从大到小排序
let arr = [10, 30, 20, 40];
arr.sort(function(item1, item2) {
// item1 - item2 是从小到大排序
return item1 - item2;
});
// 结果为:[10, 20, 30, 40]
item1:必须。当前元素
item2:必须。下一个元素
reduce()
计算数组元素相加的总和
let arr = [10, 20, 30, 40];
arr.some(function(total, item, index, arr) {
return total + num;
});
// 结果为:100
total:必需。初始值, 或者计算结束后的返回值。
item:必需。当前元素
index:可选。当前元素的索引值
arr: 可选。当前元素所属的数组对象。
闭包
闭包(closure)指有权访问另一个函数作用域中变量的函数。简单理解就是 ,一个作用域可以访问另外一个函数内部的局部变量。
function fn1 () {
let num = 100;
function fn2 () {
console.log(num);
}
fn2();
}
fn1(); // fn1() 变量在fn1()中,fn1() 就是闭包函数
变量的作用域
变量根据作用域的不同分为两种:全局变量和局部变量。
-
函数内部可以使用全局变量。
-
函数外部不可以使用局部变量。
-
当函数执行完毕,本作用域内的局部变量会销毁。
立即执行函数
/ 语法格式
// ()();
(
function (形参) {
}
)(实参);
闭包的作用
作用:延伸变量的作用范围。
简单理解:当函数执行完毕时,本作用域的局部变量不会销毁。
var arr = [];
for (var i=0; i<10; i++) {
// 产生一个小闭包
(function(i) {
arr[i] = function () {
console.log(i);
}
})(i);
};
for (var j=0; j<arr.length; j++) {
console.log(arr[j]());
};
/ 语法
(function(形参) {
console.log();
})(实参);
模拟场景:列表绑定点击事件,获取点击第几项
模拟场景,不推荐列表点击事件这么写,仅用于需要留存变量时使用
var lis = document.querySelectorAll('ul li');
for (var i=0; i<lis.length; i++) {
(
function (i) {
lis[i].onclick = function () {
console.log(i);
}
}
)(i);
}
递归
如果一个函数在内部可以调用其本身,那么这个函数就是递归函数。
简单理解:函数内部自己调用自己,这个函数就是递归函数
注意:递归函数的作用和循环效果一样,由于递归很容易发生“栈溢出”错误(stack overflow),所以必须要加退出条件return。
递归求阶乘
阶乘:1 * 2 * 3 * 4 * … * n
function fn (n) {
if (n == 1) {
return 1;
}
return n * fn(n-1);
}
console.log(fn(4));
// 执行顺序:n * n-1 * n-2 * ... * 1
递归求斐波那契
斐波那契(兔子序列):前一项加后一项,循环计算
function fn (n) {
if (n == 1 || n == 2) {
return 1;
}
return fn(n-1) + fn(n-2);
}
console.log(fn(8));
// 执行顺序:n + n-1 + n-2 + ... + 1
递归扁平化数组
思路,判断每一项是否为数组,是数组
let arr = [1, [2, [3, [4, 5, [7, 8, 9]]]], 6];
let arrNew = [];
function fn(any) {
for (let i=0; i<any.length; i++) {
Array.isArray(any[i]) ? fn(any[i]) : arrNew.push(any[i]);
};
};
fn(arr);
console.log(arrNew);
扩展:flat 方法 扁平化数组
flat() 方法创建一个新数组,其中所有子数组元素都以递归方式连接到该数组中,直到达到指定的深度为止。
返回值:一个新的数组,其中包含子数组元素。
/ 语法格式:
flat(depth);
// depth:指定嵌套数组结构应展平至多深的深度级别。默认为1
arr.flat(10000);
递归复制文件夹
模拟熊猫烧香病毒
MoveFile 方法
将指定文件或文件夹从一个位置移动到另一个位置
object.MoveFile(source, destination);
object:必须。应为 FileSystemObject 的名称
source:必须。需要移动的文件路径,source 参数的字符串只能在路径的最后成分中包含通配字符
destination:必须。文件要移到的路径。 destination 参数不能包含通配字符
注意:
如果 source 包含了通配字符,或者 destination 以路径分隔符 () 结束,那么将假定 destination 指定了一个已有的文件夹,匹配的文件将移入其中。 否则,将假定 destination 为需要创建的目的文件名。 无论哪种情况,如果移动的是单个文件,将有三种可能:
- 如果 destination 不存在,那么那么文件将被移动。 这是普通情况。
- 如果 destination 是已经存在了的文件,那么将出错。
- 如果 destination 是目录,那么也将出错。
**重要: **只有在操作系统支持时,才能通过这种方法在卷之间移动文件。
CopyFile 方法
从一个位置向另一个位置移动一个或多个文件
object.CopyFile ( source, destination, overwrite );
object:必须。应为 FileSystemObject 的名称
source:必须。指定文件字符串,可以包含通配字符来复制一个或多个文件
destination:必须。目的字符串,文件将从 source 复制到这里。 不允许通配字符
overwrite:可选项。 Boolean 值,指明是否覆盖已有文件。 如果为 true ,则文件将被覆盖;如果为 false,则文件不会被覆盖。 默认的是 true。 注意,如果 destination 设置了只读属性,那么无论 overwrite 的值是什么,CopyFile 都会失败。
MoveFolder 方法
从一个位置向另一个位置移动一个或多个文件夹
object.MoveFolder (source, destination);
object:必须。 应为 FileSystemObject 的名称。
source:必须。 要移动的文件夹的路径。 source 参数的字符串只能在路径的最后成分中包含通配字符。
destination:必须。文件夹要移入的路径。 destination 参数不能包含通配字符。
注意:
如果 source 包含了通配字符,或者 destination 以路径分隔符 () 结束,那么将假定 destination 指定的是已经存在了的文件夹,匹配的文件将移入其中。 否则将假定 destination 是需要创建的目的文件夹的名称。 无论哪种情况,如果移动的是单个文件夹,将会有三种可能:
- 如果 destination 不存在,那么文件夹将被移动。 这是普通情况。
- 如果 destination 是已有的文件,那么将出错。
- 如果 destination 是目录,那么也将出错。
如果 source 中使用的通配字符无法匹配任何文件夹,那么也将出错。 MoveFolder 方法在遇到第一个错误时终止。 出错后不会试图回滚出错前所做的修改。
重要 : 只有在操作系统支持时,才能通过这个方法在卷之间移动文件夹。