JavaScript构成
- BOM 操作浏览器对象
- DOM 操作文档对象
- ECMAScript 基础语法
ECMAScript介绍
- ECMAScript 是对应 js 的基础语法,里面包含 js 中除 dom 操作和 bom 的所有内容。ECMAScript主要拆分为俩个单词 ECMA (欧洲计算机协会) 、Script (脚本)。
- ECMAScript 简称(es)他主要的版本有 ES3、ES5、ES6...对应的版本管理以及切换是由不同兼容问题产生的。
- 低版本的兼容就比较好,高版本的兼容性较差。在项目中我们可以使用 bable.js 来进行生成代码的版本切换(后续框架中必然使用的)。ES3为基础版本他支持市面常用的所有浏览器,ES5支持市面上大多数浏览器, ES6只支持高版本浏览器。
ECMAScript的版本
- ES3 基础版本(大多数的基础内容都属于es3)
- ES5 (ES2009) 他在es3上增强对应的规范性以对应的方法
- ES6 (ES2015) 他在es5的基础上扩展了对应的类及对应的处理
ES5新增内容
怪异模式
平常书写代码没有多大的规范性、比较随意,平常的这种模式就被称为怪异模式。
严格模式
严格模式是采用具有限制性 JavaScript 变体的一种方式,具备规范性。
严格模式的书写
- 使用 use strict 来声明且必须书写在首行
<script>
'use strict'
hello = '你好'
console.log(hello) //报错,因为在严格模式下,必须要声明
</script>
严格模式的特性
- 声明变量必须使用var关键词声明
- 函数中的 this 不允许指向全局对象(global)(window)
- arguments 中的实参不同步:严格模式下,函数的 arguments 对象会保存函数被调用时的原始参数。arguments[i] 的值不会随与之相应的参数的值的改变而变化,同名参数的值也不会随与之相应的 arguments[i] 的值的改变而变化。
- 函数名的参数唯一
- 严格模式要求一个对象内的所有属性名在对象内必须唯一
- 函数声明只处于上下文对象中
- 禁止使用八进制方法
- 将一切不规范的地方全部抛出错误
【示例】:函数声明只处于上下文对象中
"use strict";
if (true) {
function f() { } // !!! 语法错误
f();
}
for (var i = 0; i < 5; i++) {
function f2() { } // !!! 语法错误
f2();
}
function baz() { // 合法
function eit() { } // 同样合法
}
数组新增的高阶函数
高阶函数就是以函数作为参数的函数被称为高阶函数
- forEach 遍历 (返回值为void):没有返回值
var arr = ['a','b','c','d']
//传入的函数为操作函数
//传入的函数有三个参数 分别为遍历的值 遍历的下标 遍历的数组
arr.forEach(function(value,index,array){
console.log(value,index,array)
//输出值为
// a 0 ['a', 'b', 'c', 'd']
// b 1 ['a', 'b', 'c', 'd']
// c 2 ['a', 'b', 'c', 'd']
// d 3 ['a', 'b', 'c', 'd']
})
- map 遍历 (返回值是数组 且返回的数组个数和遍历的数组个数一致)
var arr = ['1', '2', '3', '4']
var nums = arr.map(function(v,i,arr){
// 遍历数组,找出下标为偶数的下标并输出
if(i%2 == 0){
return i
}
})
console.log(nums)//[0,undefined,2,undefined]
forEach 和 map 的相同点和区别
【相同点】
- 都是循环遍历数组中的每一项。
- forEach() 和 map() 里面每一次执行匿名函数都支持3个参数:(遍历的值value,遍历的下标index,遍历的数组 arr)
- 匿名函数中的 this 都是指向 Window。
- 只能遍历数组
【区别】
- 区别在于forEach() 没有返回值,map() 有返回值
- forEach() 会改变原数组,map() 不会改变原数组
- filter 过滤 (返回的是一个数组)
//filter用于过滤
//里面传入的对应的函数一定返回值boolean
//true就是添加的返回的数组 如果是false就不添加
//v表示对应的值 i表示下标 arr表示数组
var filterArr = ['a', 'b', 'c', 'ab'].filter(function (v, i, arr) {
return /a/.test(v) // 过滤含a的字符并返回成一个数组
})
console.log(filterArr) // ['a', 'ab']
- every 每个都满足条件返回 true (传入的函数的必须返回boolean)
//every 当前是否每个都满足条件
var is = ['1', '2', '3', '4'].every(function (v, i, arr) {
return v > 3
})
console.log(is) //false
- some 只有有一个满足条件返回false (传入的函数的必须返回的boolean)
//some当前是否存在满足条件的
var is = ['1', '2', '3', '4'].some(function (v, i, arr) {
return v > 3
})
console.log(is)//true
- reduce:从左到右,用于计算
语法:reduce(function(prev,current,i,arr){},初始值)
第一个参数为处理函数 ,第二个参数为初始值 (如果没有设置默认为第一个 如果设置那么就对应设置的值)
- prev :前面的结果值 (默认为数组的第一个值), 如果第二个参数设置了初始值那么 prev 值为初始值
- current :当前值 (默认从第二个开始) 设置了第二个参数那么默认从第一个开始
- i :默认从下标为1开始 设置了第二个参数那么下标从0开始
【示例】 求数组内元素的和
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
})
console.log(arr, sum);
打印结果:
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
var arr = [1, 2, 3, 4];
var sum = arr.reduce(function(prev, cur, index, arr) {
console.log(prev, cur, index);
return prev + cur;
},0) //注意这里设置了初始值
console.log(arr, sum);
打印结果:
0 1 0
1 2 1
3 3 2
6 4 3
[1, 2, 3, 4] 10
- reduceRight :从右到左开始计算
var numbers = [2, 45, 30, 100];
function getSum(total, num,i,arr) {
console.log(total, num, i);
return total - num;
}
console.log( numbers.reduceRight( getSum ) )//23
打印结果:
100 30 2
70 45 1
25 2 0
23
高阶函数的手动封装实现
- forEach
var arr = [1,2,3,4]
//封装myForEach
function myForEach(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//遍历执行处理函数
for (var i = 0; i < arr.length; i++) {
callback(arr[i], i, arr)
}
}
//调用
myForEach(function (v, i, arr) {
console.log(v, i, arr)
})
打印结果:
1 0 [1, 2, 3, 4]
2 1 [1, 2, 3, 4]
3 2 [1, 2, 3, 4]
4 3 [1, 2, 3, 4]
- map:不会改变原数组,返回一个新的数组
var arr = [1, 2, 3, 4]
//封装myMap
function myMap(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//返回的内容
var results = []
//遍历执行处理函数
for (var i = 0; i < arr.length; i++) {
results.push(callback(arr[i], i, arr))
}
return results
}
myMap(function(v, i, arr) {
console.log(v + 'hello', i, arr);
console.log(myMap(function(v) {
return v + 'hello'
}))
})
打印结果:
1hello 0 [1, 2, 3, 4]
2hello 1 [1, 2, 3, 4]
3hello 2 [1, 2, 3, 4]
4hello 3 [1, 2, 3, 4]['1hello', '2hello', '3hello', '4hello']
- every
var arr = [1, 2, 3, 4]
//封装myEvery
function myEvery(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//遍历执行处理函数
for (var i = 0; i < arr.length; i++) {
//只要有一个false,那么直接返回false
if (!callback(arr[i], i, arr)) {
return false
}
}
return true
}
console.log(myEvery(function(v){return v<10}))
打印结果:
true
- some
var arr = [1, 2, 3, 4]
//封装mySome
function mySome(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//遍历执行处理函数
for (var i = 0; i < arr.length; i++) {
//只要有一个true,那么直接返回true
if (callback(arr[i], i, arr)) {
return true
}
}
return false
}
console.log(mySome(function (v) {
return v >= 4
}))
打印结果:
true
- filter:不会改变原数组
var arr = [1, 2, 3, 4]
//封装myFilter
function myFilter(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//准备一个返回的数组
var results = []
//遍历执行处理函数
for (var i = 0; i < arr.length; i++) {
//当里面返回的true填入到数组
if (callback(arr[i], i, arr)) {
results.push(arr[i])
}
}
return results
}
console.log(myFilter(function(v){return v>2}))
打印结果:
[3, 4]
- reduce *
var arr = [1, 2, 3, 4]
//myReduce
function myReduce(callback, value) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
//value被传递的情况
var index = 0
var previous = value
//如果value值没有被传递 那么我的遍历从下标1开始 初始值为对应的下标为0的元素
if (typeof value == 'undefined') {
//判断是否为空数组
if(arr.length == 0){
throw new Error('Reduce of empty array with no initial value')
}
index = 1
previous = arr[0]
}
//遍历计算值
for(; index < arr.length ; index++){
//调用传入的函数 得到对应的结果值 再覆盖对应的结果
previous = callback(previous,arr[index],index,arr)
}
//返回结果
return previous
}
console.log(myReduce (function (prev,current , index , arr){
console.log( previous , current , index , arr);
return prev+current
},20))
打印结果:
20 1 0 [1, 2, 3, 4]
21 2 1 [1, 2, 3, 4]
23 3 2 [1, 2, 3, 4]
26 4 3 [1, 2, 3, 4]
30
- reduceRight
var arr = [1, 5, 3, 2, 9]
// reduceRight
function myReduceRight(callback, value) {
var index = arr.length - 1
var prev = value //前面的值
if (typeof callback != 'function') {
throw new Error('参数错误')
}
if (typeof value == 'undefined') {
if (arr.length == 0) {
throw new Error('Reduce of empty array with no initial value')
}
index = arr.length - 1
var current = arr[arr.length]
prev = 0
}
for (var i = index; i >= 0; i--) {
prev = callback(prev, arr[i], i, arr)
}
return prev
}
console.log(myReduceRight(function(prev, current, i, arr) {
console.log(prev, current, i, arr)
return prev + current
}, 2));
打印结果:
2 9 4 [1, 5, 3, 2, 9]
11 2 3 [1, 5, 3, 2, 9]
13 3 2 [1, 5, 3, 2, 9]
16 5 1 [1, 5, 3, 2, 9]
21 1 0 [1, 5, 3, 2, 9]
22
- filter
var arr = [1, 5, 3, 2, 9]
function myFilter(callback) {
if (typeof callback != 'function') {
throw new Error('参数错误')
}
var result = []
for (var i = 0; i < arr.length; i++) {
if (callback(arr[i], i, arr)) {
result.push(arr[i])
}
}
return result
}
console.log(myFilter(function(v) {
return v > 2
}));
打印结果:
[5, 3, 9]
this指向的改变(Function对象的方法)
- bind (返回一个函数 需要手动调用),传参跟对应执行函数传的参是一样的
- apply(自动调用 返回值是对应的函数执行的结果),传参必须是数组
- call (自动调用 返回值也是对应的函数执行的结果),传参必须是一个个的元素
【注意】:
- 传参个数要相同,少传参会返回 NaN,多传参不会调用多传的参数
- bind 函数执行完返回的函数不能被 apply 和 call 进行二次更改 this 指向
var obj = {
sayHi: function() {
console.log(this); //返回obj对象
}
}
obj.sayHi()function sayHello() {
console.log(this); //返回的是window
}
sayHello()
// bind、call、apply用来改变this的指向
var fn = obj.sayHi.bind(window)
fn() //打印得是window
console.log(fn); //返回一个新的函数
console.log(fn == obj.sayHi); //false
console.log(sayHello.apply(obj)); //更改this指向obj
console.log(sayHello.call(document)); //更改this指向document
//------------------------------------------
function sum(num1, num2) {
return num1 + num2
}
// 传递参数跟对应的函数执行传参是一样的
console.log(sum.bind(String)(2, 3));
// 传递参数是对应的数组
console.log(sum.apply(document, [2, 3]));
// 传递参数时一个个的元素
console.log(sum.call(document.body, 2, 1));
getter setter (对象里面)
- get 用于获取,必须是访问属性名
- set 用于设置,必须是访问属性名
var obj = {
_name:'hello',
get name() {
console.log('getter 调用了')
// return this.name + '张三' 出错无限递归
return this._name +'张三'
},
set name(value) {
this._name = value
console.log('setter 调用了')
}
}
console.log(obj.name) //调用getter
obj.name = 'hi'//调用setter
console.log(obj.name) //调用getter
打印结果:
getter 调用了
hello张三
setter 调用了
getter 调用了
hi张三
【 补充新增】
- 字符串的 trim 方法 (去前后空格)
- 数组的静态方法 Array.isArray:返回 Boolean 值
- 数组的 indexOf 及 lastIndexOf
- JSON 的序列化方法及反序列化方法:JSON.stringify(),JSON.parse()
- Object 的相关方法:object.defineProperty 等
//静态方法就是首字母大写的类型(class类)名来调用的方法 (static修饰的)
console.log(Array.isArray([])) //true 判断是否为数组
console.log(['a','b','c'].indexOf('a'))//0 获取对应的第一个出现的下标
console.log(['a','b','c','a'].lastIndexOf('a'))//3 从后往前获取对应的第一个出现的
下标
console.log(['a','b','c'].indexOf('a',1))//-1 第二个指定是对应的开始下标找不到返
回-1
console.log(['a','b','c'].lastIndexOf('a',1))//0