目录
JS的组成:
- ECMAScript --JavaScript语法 --JS基础
- DOM --页面文档对象模型 --Web APIs
- BOM --浏览器对象模型 --Web APIs
JS基础阶段 | Web APIs阶段 |
---|---|
学习的是ECMAScript标准规定的基本语法 | Web APIs是W3C组织的标准 |
要求掌握JS基本语法 | 主要学习DOM和BOM |
只学习基本语法,做不了常用的网页交互效果 | 是JS所独有的部分 |
目的是为JS后面的课程打基础、做铺垫 | 主要学习页面交互功能 |
一、作用域
作用域指一个变量作用的范围
(一)全局作用域
- 直接编写在script标签的JS代码,都在全局作用域
- 全局作用域在页面打开时创建,在页面关闭时销毁
- 在全局作用域中有一个全局对象window,它代表的是一个浏览器的窗口,由浏览器创建,可用直接使用
- 在全局作用域中,创建的变量都会作为window对象的属性保存
(二)局部作用域(函数作用域)
- 调用函数时创建函数作用域,函数执行完毕后,作用域销毁
- 每调用一次函数就会创建一个新的函数作用域,它们之间是相互独立的
- 在函数作用域中可以访问到全局作用域的变量,但全局作用域中无法访问局部的变量
- 当在函数作用域操作一个变量时,它会先在自身作用域中寻找,如果有直接使用,否则想上一级作用域寻找,直到找到为止
- 在函数中要访问全局变量可以使用window对象
- 函数作用域中也存在声明提前
二、声明提前
(一)变量的声明提前
使用var关键字声明的变量,会在所有的代码执行之前被声明
console.log(a);
var a = 123;
/**
* 结果:undefined,实际顺序:
* var a
* a.log
* a = 123
* */
(二)函数的声明提前
使用函数声明形式创建的函数function函数(){},他会在所有的代码执行之前就被创建,因此可用在函数声明前调用函数。而使用函数表达式创建的函数,不会被声明提前,所以不能在声明前调用。
fun1()
fun2()
function fun1() {
console.log('hello world1');
}
var fun2 = function () {
console.log('hello world2');
}
/**
* 结果:fun1被成功调用,打印hello world1
* fun2调用失败,函数只被定义但未声明,程序报错
* 实际顺序:
* */
function fun1() {
console.log('hello world1');
}
var fun2
fun1()
fun2()
fun2 = function () {
console.log('hello world2');
}
三、this
解析器在调用函数每次都会向函数内部传递进一个隐含的参数,这个隐含的参数就是this,this指向的是一个对象,根据函数的调用方式的不同,this会指向不同的对象:
- 以函数的形式调用时,this永远都是window
- 以方法的形式调用时,this就是调用方法的那个对象
四、立即执行函数
函数定义完,立即被调用,这种函数叫做立即执行函数
实现:下方为一个匿名函数,用()将其包起来形成一个闭包,再通过()进行函数调用
(function () {
console.log('hello world');
})()
||
var hello = function () {
console.log('hello world');
}
hello()
五、构造函数
将同一类型的元素通过函数封装起来,再需要声明时只需调用构造函数即可
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.showname = function () {
console.log(this.name);
};
}
var ming = new Person('小明', 18, '男')
var hong = new Person('小红', 19, '女')
var lan = new Person('小兰', 20, '男')
ming.showname()
hong.showname()
lan.showname()
上述代码虽实现了元素的封装,但之前说过,函数每执行一次就会创建一个新的方法,被调用一百次就会创建一百个方法,而这些方法都是一样的,完全没有必要,因此需要将函数中的方法写到函数外部,让所有的对象共享同一个方法:
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.showname = showname()
}
function showname() {
console.log(this.name);
};
var ming = new Person('小明', 18, '男')
var hong = new Person('小红', 19, '女')
var lan = new Person('小兰', 20, '男')
ming.showname()
hong.showname()
lan.showname()
六、原型对象
由于尽量不要在全局作用域中定义变量(会污染全局作用域的命名空间),引出了原型变量:
1、但凡创建了对象(无论是函数对象还是普通对象),都自带一个_proto_属性,可称为隐式原型,一个对象的隐式原型指向构造该对象的构造函数的原型,这也保证了实例能够访问在构造函数原型中定义的属性和方法。
2、其中函数对象除了和其他对象一样有上述_proto_属性之外,还有自己特有的属性——原型属性(prototype),这个属性是一个指针,指向一个对象,这个对象的用途就是包含所有实例共享的属性和方法(我们把这个对象叫做原型对象)。原型对象也有一个属性,叫做constructor,这个属性包含了一个指针,指回原构造函数。
- 我们所创建的每一个函数,解析器都会向函数中添加一个属性prototype,这个属性对应着一个对象,这个对象就是我们所谓的原型对象
- 如果函数作为普通函数调用prototype没有任何作用
- 当函数以构造函数的形式调用时,它所创建的对象中都会有一个隐含的属性,指向该构造函数的原型对象,我们可以通过__proto__来访问该属性
- 原型对象就相当于一个公共的区域,所有同一个类的实都可以访问到这个原型对象,因此我们可以将对象中共有的部分统一设置到原型对象那个中
- 当访问对象的一个属性或方法时,它会先在自身中寻找,如果没有,向上去父级原型对象中寻找,再没有去祖父级,最多可向上寻找两级,即寻找到祖父级。
//向原型中添加方法
Person.prototype.sayage = function () {
console.log(this.age);
}
七、数组&字符串
(一)数组的方法:
方法 | 操作 | 返回 |
---|---|---|
concat() | 连接两个或更多的数组 | 连接结果 |
join() | 把数组的所有元素放入一个字符串, 元素通过指定的分隔符进行分隔。 | |
push() | 向数组的末尾添加一个或多个元素 | 数组的新的长度 |
pop() | 删除数组的最后一个元素,长度-1 | 删除的元素 |
shift() | 删除第一个元素,长度-1 | 第一个元素 |
unshift() | 开头添加一个或多个元素 | 新长度 |
reverse() | 颠倒数组中元素顺序 | 新数组 |
sort() | 对数组的元素进行排序 | 新数组 |
slice() | 从某个已有的数组返回选定的元素 | |
splice() | 删除指定元素,并向数组添加新元素 | |
toString() | 把数组转换为字符串,并返回结果 | |
valueof() | 返回对象的原始值 |
(二)数组的遍历(迭代)
forEach
var arr = ["1111", "2222", "3333", "4444"]
/**
* 该方法需要一个函数作为参数
* 像这种函数,需要我们创建但不被我们调用的函数,称为回调函数
* 数组中有几个元素就会执行几次,每次执行时,浏览器会将遍历到的元素以实参的形式传递进去,
* 因此可以再回调函数中定义形参来获取遍历到的值
* 浏览器会在回调函数中传递三个参数(value,index,array)
* */
arr.forEach(function (a, b, c) {
console.log(a);
console.log(b);
console.log(c);
})
filter
/**
* filter()方法创建一个新的数组,新数组中的元素是通过检查指定数组中符合条件的所有元素,主要用于筛选数组
* 它直接返回一个新数组
* 浏览器会在回调函数中传递三个参数(value,index,arr)
* */
var arr = [12, 66, 4, 18];
var result = arr.filter(function (value, index, arr) {
return value >15;
})
console.log(result);
some
/**
* some()方法用于检测数组中的元素是否满足指定条件,也就是查找数组中是否有满足条件的元素
* 返回值为布尔值
* 找到第一个满足条件的元素终止循环,否则会一直找下去直到遍历整个数组
* 浏览器会在回调函数中传递三个参数(value,index,arr)
* */
var arr = [12, 66, 4, 18];
var result = arr.some(function (value, index, arr) {
return value >15;
})
console.log(result);
(三)sort排序存在的问题
由于sort排序默认是按照Unicode编码排序的,因此对数字进行排序时,像11、100这样的数字会排在1和2之间,这样会得到一个错误的结果
我们可以通过在sort中添加回调函数来指定排序规则:
var arr = [1, 2, 3, 2, 1, 3, 4, 2, 5, 3, 3, 0, 9, 2, 1];
arr.sort(function (a, b) {
return a-b;
// if (a > b) {
// return 1;
// }else if (a < b) {
// return -1;
// }else {
// return 0;
// }
})
该回调函数返回值:遍历过程中,大于1时交换两元素位置,为0表相等可不动,为负数不动
(四)数组的方法:
indexof() | 查找给定元素的第一个索引 |
charAt(index) | 返回index处的字符 |
charCodeAt(index) | 返回index处的ASCⅡ码 |
str[index] | 获取指定位置处字符串 |
concat(str1, str2, ...) | 将str1,str2,...连接 |
substr(start, length) | 从start处开始取length长度的内容 |
slice(strat, end) | 从start处取到end(end取不到) |
substring(start, end) | 与slice基本相同,但不接受负值 |
replace(str1, str2) | 将str1替换为str2 |
split('||') | 逢‘||’分隔 |
八、正则表达式
正则表达式用于定义一些字符串的规则,
- 计算机可以根据正则表达式,来检查一个字符串是否符合规则,
- 获取将字符串中符合规则的内容提取出来
(一)基础概念
// 创建正则表达式对象
var reg = new RegExp("a"); //(正则表达式,匹配模式)
var str = "a";
/**
* 正则表达式的方法test():
* 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,返回ture/false
* */
var result = reg.test(str)
------------------------------------------------
/**
* 匹配模式
* i:忽略大小写
* g:全局匹配模式
* */
var reg = new RegExp("a", "i"); //(正则表达式,匹配模式)
var str = "A";
/**
* 正则表达式的方法test():
* 使用这个方法可以用来检查一个字符串是否符合正则表达式的规则,返回ture/false
* */
var result = reg.test(str)
// 使用字面量创建正则表达式
var reg = /a/i;
var result = reg.test("a")
// 使用[]实现“|”的效果
reg = /a|b/;
||
reg = /[ab]/;
reg = /[abcdefg]/;
||
reg = /[a-g]/;
reg = /[^ab]/ //除了ab其他元素都匹配
(二)使用方法
var str1 = "1A2b3c4D5e6f7G8h9";
/**
* 使用spilt将字符串拆分成一个数组
* 如果在str中想按字母将数组拆分,可以利用正则表达式来实现
* */
var result1 = str1.split(/[A-Z]/i);
console.log(result1);
// 使用search()+正则查找是否存在abc或aec或afc
var str2 = "hello abc hello aec hello afc"
var result2 = str2.search(/a[bef]c/);
console.log(result2);
// 使用match()+正则寻找提取条件的内容
var str3 = "1A2b3c4D5e6f7G8h9";
// 由于match找到第一个符合要求的就会停止寻找,因此想要所有匹配内容需进入全局匹配模式g
var result3 = str3.match(/[A-Z]/ig)
console.log(result3);
(三)语法
语法 | 等同于 | 描述 |
---|---|---|
/aaaaaa/ | /a{6}/ | {n}表示正好出现n次,可写为{n,m}表示出现n~m次 |
/^a/ | 表示检查字符串是否以a开头 | |
/a$/ | 表示检查字符串是否以a结尾 | |
/^a$/ | 以a开头且结尾(都是这一个a,因此只有字符串“a”能匹配) |
/**
* 使用正则简单判断手机号是否符合标准
* 标准:
* 1、以1开头 ^1
* 2、第二位只能是3-9 [3-9]
* 3、全长11位数字 [0-9]{9}$
*
* */
var str4 = "19858190775";
var reg = /^1[3-9][0-9]{9}$/;
var result4 = reg.test(str4);
console.log(result4);
(四)元字符
元字符是拥有特殊含义的字符:
元字符 | 描述 |
---|---|
. | 查找单个字符(除了换行和结束符其他所有字符均可符合) |
\w | 查找单词字符 |
\W | 查找非单词字符 |
\d | 查找数字 |
\D | 查找非数字字符 |
\s | 查找空白字符 |
\S | 查找非空白字符 |
\b | 匹配单词边界 |
\B | 匹配非单词边界 |
\0 | 查找NUL字符 |
\n | 查找换行符 |
\f | 查找换页符 |
\r | 查找回车符 |
\t | 查找制表符 |
\v | 查找垂直制表符 |
\xxx | 查找以八进制数xxx规定的字符 |
\xdd | 查找以十六进制数dd规定的字符 |
\uxxxx | 查找以十六进制数xxxx规定的Unicode字符 |
(五)量词符
量词 | 说明 |
* | 重复零次或更多次 |
+ | 重复一次或更多次 |
? | 重复零次或一次 |
{n} | 重复n次 |
{n,} | 重复n次或更多次 |
{n,m} | 重复n到m次 |
(六)replace
//利用正则+replace实现字符的替换
var str = 'andy和red';
var newStr = str.replace(/andy/, 'baby');
console.log(newStr);
repalce方法可以实现替换字符串的操作,但只能实现第一个符合要求字符的替换,因此如果想要替换所有符合要求的字符,需要加上全局匹配模式g。
replace可以实现一些类似敏感词替代等功能
九、定时&延时
- 开启定时器
setInterval(回调函数, 间隔时间) // 单位毫秒
返回一个Number类型的数据,用来作为定时器的唯一标识(多个定时器时就可以用来进行区分)
setInterval(function() {
alert('hello');
}, 1000);
- 关闭定时器
clearInterval(定时器标识);
- 延时调用
setTimeout(function() {
alert('hello');
}, 10000)
十、节流阀
目的:防止轮播图按钮连续点击造成播放过快
实现:当上一个函数动画内容执行完毕,再去执行下一个函数动画,让事件无法连续触发。
核心思路:利用回调函数,添加一个变量来控制,锁住函数和解锁函数。
开始设置一个变量var flag = true;(信号量)
后续即为PV操作。