1.数据类型
js中的数据类型分为两类
①基本(原始)数据类型
number
string字符串
boolean布尔值
null
undefined
bigint 可以表示超出number安全整数(Number.MAX_SAFE_INTEGER)范围的大整数
symbol 创建后独一无二且不可变
②引用数据类型
object对象
array数组
function函数
原始数据类型和引用数据类型的区别:
原始数据类型存储在栈中 引用数据类型存储在堆中
2.数据类型检测方式
①typeof
数组、对象、null都会被识别成object
②instanceof
console.log(2 instanceof Number) //false
console.log([] instanceof Array) //true
只能判断引用数据类型
可以正确判断对象类型
通过判断在其原型链中能否找到该类型的原型
③constructor
console.log(('str').constructor === String) //true
判断数据类型+对象实例通过constructor对象访问它的构造函数
如果创建一个对象来改变它的原型,就不能用constructor来判断了
④Object.prototype.toString.call()
3.对JSON的理解
基于文本的轻量级的数据交换格式,可以被任何编程语言读取和作为数据格式来传递
前后端数据交换的方式:
在前端将一个符合JSON格式的数据结构序列化为json字符串
JSON.stringify()
传递到后端,后端将其解析成对应的数据结构
JSON.parse()
JSON中对象格式更严格,如属性值不能为函数,不能出现NaN
4.脚本延迟加载的方法
延迟加载:等页面加载完成后再加载JS文件,有助于提高页面加载速度
HTML中浏览器遇到<script>标签时默认会暂停对HTML的解析去下载并执行js文件
①defer属性
给js脚本添加defer属性
浏览器异步下载JS文件,不会立即执行,等HTML解析完成后再顺序执行
让脚本的加载与文档的解析同步,在文档解析完成后再执行这个脚本文件
如果有多个带defer属性的<script>标签,按照在HTML中出现的顺序依次执行
②async属性
浏览器异步下载JS文件,下载完成后会立即暂停HTML解析,执行JS文件
如果有多个带async属性的<script>标签,加载顺序不确定
③动态创建DOM方式
可以对文档的加载事件进行监听,文档加载完成后再动态创建script标签来引入js脚本
④setTimeout
⑤把js脚本放在文档底部
5.类数组对象
拥有length属性和若干索引属性的对象
和数组类似但不能调用数组的方法
常见的类数组对象:
arguments
DOM方法的返回结果
函数
常见的类数组转化为数组的方法:
①call调用数组的slice方法
Array.prototype.slice.call(arrayLike)
②call调用数组的splice方法
Array.prototype.splice.call(arrayLike,0)
③apply调用数组的concat方法
Array.prototype.concat.apply([],arrayLike)
④Array.from
Array.from(arrayLike)
遍历类数组:
① ② ③
6.数组的原生方法
数组和字符串的转换 toString() toLocalString() join()
尾部操作方法 pop() push()
首部操作方法 shift() unshift() reverse() sort()
连接方法 concat()
截取方法 slice()
插入方法 splice()
归并方法 reduce() reduceRight()
join()
把数组中的所有元素转换成一个字符串
元素通过指定的分隔符分隔,默认逗号
var arr = [1,2,3];
console.log(arr.join()); // 1,2,3
console.log(arr.join("-")); // 1-2-3
console.log(arr); // [1, 2, 3](原数组不变)
通过join()方法可以实现重复字符串
function repeatString(str, n) {
//一个长度为n+1的空数组用string去拼接成字符串,就成了n个string的重复
return new Array(n + 1).join(str);
}
console.log(repeatString("abc", 3)); // abcabcabc
console.log(repeatString("Hi", 5)); // HiHiHiHiHi
push()和pop()
push从数组末尾向数组添加元素,可以添加一个/多个,返回数组长度
pop删除数组的最后一个元素并返回删除的元素
var arr = ["Lily","lucy","Tom"];
console.log(arr.push("Jack","Sean")); // 5
console.log(arr); // ["Lily", "lucy", "Tom", "Jack", "Sean"]
console.log(arr.pop()); // Sean
console.log(arr); // ["Lily", "lucy", "Tom", "Jack"]
shift()和unshift()
shift删除数组的第一个元素,返回第一个元素
unshift向数组的开头添加一个/多个元素,返回数组长度
var arr = ["Lily","lucy","Tom"];
console.log(arr.unshift("Jack","Sean")); // 5
console.log(arr); //["Jack", "Sean", "Lily", "lucy", "Tom"]
console.log(arr.shift()); // Jack
console.log(arr); // ["Sean", "Lily", "lucy", "Tom"]
reserve()
颠倒数组中元素的顺序
var arr = [13, 24, 51, 3];
console.log(arr.reverse()); //[3, 51, 24, 13]
console.log(arr); //[3, 51, 24, 13](原数组改变)
sort()
排序,默认顺序为按字母升序
var arr1 = ["a", "d", "c", "b"];
console.log(arr1.sort()); // ["a", "b", "c", "d"]
arr2 = [13, 24, 51, 3];
console.log(arr2.sort()); // [13, 24, 3, 51]
console.log(arr2); // [13, 24, 3, 51](原数组被改变)
也可以接收一个比较函数作为参数
比较函数接收两个参数,如果第一个参数应该位于第二个之前则返回一个负数,如果两个参数相等则返回 0,如果第一个参数应该位于第二个之后则返回一个正数。
function compare(value1, value2) {
if (value1 < value2) {
return -1;
} else if (value1 > value2) {
return 1;
} else {
return 0;
}
}
arr2 = [13, 24, 51, 3];
console.log(arr2.sort(compare)); // [3, 13, 24, 51]
concat()
连接两个或多个数组
不改变原有数组,返回被连接数组的一个副本
var arr = [1,3,5,7];
var arrCopy = arr.concat(9,[11,13]);
console.log(arrCopy); //[1, 3, 5, 7, 9, 11, 13]
console.log(arr); // [1, 3, 5, 7](原数组未被修改)
传入的不是数组,则直接把参数添加到数组后面,
如果传入的是数组,则将数组中的各个项添加到数组中
slice()
返回从原数组中截取的新数组
接收一/两个参数,返回项的起始和结束位置
只有一个参数,返回从参数指定位置开始到当前数组末尾的所有项
接收两个参数,返回起始至结束,但不包括结束位置的项
参数有负数时,将负数加上数组长度的值
var arr = [1,3,5,7,9,11];
console.log(arr.slice(1)); //[3, 5, 7, 9, 11]
console.log(arr.slice(1,4)); //[3, 5, 7]
console.log(arr.slice(1,-2)); //[3, 5, 7]
console.log(arr.slice(-4,-1)); //[5, 7, 9]
console.log(arr); //[1, 3, 5, 7, 9, 11](原数组没变)
splice()
可以实现删除、插入和替换
①删除
可以删除任意数量的项 接收两个参数:要删除的第一项的位置和要删除的项数 返回删除的元素
var arr = [1,3,5,7,9,11];
var arrRemoved = arr.splice(0,2);
console.log(arr); //[5, 7, 9, 11](原数组改变)
console.log(arrRemoved); //[1, 3]
②向指定索引处添加元素
传参:起始位置,0(要删除的项数),要插入的项
var array1 = [22, 3, 31, 12];
array1.splice(1, 0, 12, 35); //[]
console.log(array1); // [22, 12, 35, 3, 31, 12]
③替换指定位置的元素
可以向指定位置插入任意数量的项,同时删除任意数量的项
传参:起始位置,要删除的项数,要插入的项
const array1 = [22, 3, 31, 12];
array1.splice(1, 1, 8); //[3]
console.log(array1); // [22, 8, 31, 12]
indexOf()和lastIndexOf()
接收两个参数:要查找的项和查找的起点位置
indexOf:从数组开头(0)开始向后查找
lastIndexOf:从数组末尾向前查找
返回要查找的项在数组中的位置,没找到返回-1
比较时使用全等操作符
var arr = [1,3,5,7,7,5,3,1];
console.log(arr.indexOf(5)); //2
console.log(arr.lastIndexOf(5)); //5
console.log(arr.indexOf(5,2)); //2
console.log(arr.lastIndexOf(5,4)); //2
console.log(arr.indexOf("5")); //-1
forEach()
遍历数组,没有返回值
参数都是function类型,默认有传参
传参为:遍历的数组内容,对应的数组索引,数组本身
map()
返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值
不会改变原数组
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.map(function(item){
return item*item;
});
console.log(arr2); //[1, 4, 9, 16, 25]
filter()
过滤
返回新数组,不改变原数组
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var arr2 = arr.filter(function(x, index) {
return index % 3 === 0 || x >= 8;
});
console.log(arr2); //[1, 4, 7, 8, 9, 10]
fill() ES6新增
使用特定值填充数组
改变了原数组
只传一个参数时,用参数值填充整个数组
let arr = [1, 2, 3, 'cc', 5];
arr.fill(1);
console.log(arr);//[1,1,1,1,1];
传三个参数:填充数值,起始位置参数,结束位置参数(不包括结束位置的元素)
let arr = [1, 2, 3, 'arr', 5];
arr.fill(1, 2);
console.log(arr);//[1,2,1,1,1]
arr.fill(0, 1, 3);
console.log(arr);//[1,0,0,1,1];
every()
判断数组中的每一项是否满足条件
所有项都满足才返回true
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.every(function(x) {
return x < 10;
});
console.log(arr2); //true
var arr3 = arr.every(function(x) {
return x < 3;
});
console.log(arr3); // false
some()
判断数组中是否存在满足条件的项
只要有一项满足就返回true
var arr = [1, 2, 3, 4, 5];
var arr2 = arr.some(function(x) {
return x < 3;
});
console.log(arr2); //true
var arr3 = arr.some(function(x) {
return x < 1;
});
console.log(arr3); // false
includes()
判断一个数组是否包含一个指定的值,是返回true,否则false
接收两个参数:查找的元素值,开始查找元素的位置(可不传)
const array1 = [22, 3, 31, 12, 'arr'];
const includes = array1.includes(31);
console.log(includes); // true
使用===运算符来进行比较,但NaN被认为与自身相等
reduce()和reduceRight()
reduce()接收两个参数,回调函数reducer和初始值(可不传)
reducer接收四个参数:
acc:累加器,存储上一次回调的返回值
current:当前的数组元素
index:当前的数组元素索引
array:原数组
如果传了第二个参数,reduce方法会在此基础上开始累积执行
如数组求和
const arr = [1, 2, 3, 4]
const accumulator = (total, current, currentIndex, arr) => {
console.log(total, current, currentIndex, arr);
return total + current
}
console.log(arr.reduce(accumulator))
reduce从头开始 reduceRight从末尾开始
toString()和toLocalString()
将数组转换成字符串
const array1 = [22, 3, 31, 12];
console.log(array1.toLocaleString()); // 22,3,31,12
console.log(array1.toString()); // 22,3,31,12
tolocalstring会根据用户的区域设置进行格式化
find()和findIndex()
接收两个参数:回调函数,可选值用于指定回调函数内部的this
回调函数接收三个参数:
数组的某个元素,该元素的索引位置,数组本身
回调函数会在给定的元素满足定义的条件时返回true
find()和findIndex()会在回调函数第一次返回true时停止查找
find()返回匹配的值
findIndex()返回匹配位置的索引
let arr = [1, 2, 3, 'arr', 5, 1, 9];
console.log(arr.find((value, keys, arr) => {
return value > 2;
})); // 3 返回匹配的值
console.log(arr.findIndex((value, keys, arr) => {
return value > 2;
})); // 2 返回匹配位置的索引
传递第二个参数时,回调函数内部的this指向该参数
在使用非箭头函数作为回调函数时使用
const team = {
members: ['Alice', 'Bob', 'Charlie'],
leader: 'Alice',
findLeader() {
return this.members.find(function(member) {
// this 指向 team 对象(由 thisArg 绑定)
return member === this.leader;
}, this); // 传递 this 作为 thisArg
}
};
console.log(team.findLeader()); // "Alice"
copyWithin()
从数组的指定位置拷贝元素到数组的另一指定位置中
会改变原数组
let arr = [1, 2, 3, 'arr', 5];
arr.copyWithin(3, 0);
console.log(arr);//[1,2,3,1,2]
默认情况下会复制到数组末尾
传第三个参数指定复制停止的位置
let arr = [1, 2, 3, 'arr', 5, 9, 17];
//从索引3的位置开始粘贴
//从索引0的位置开始复制
//遇到索引3时停止复制
arr.copyWithin(3, 0, 3);
console.log(arr);//[1,2,3,1,2,3,17]
flat()
按一个可指定的深度递归遍历数组,
将所有元素和遍历到的子数组里的元素合并为一个新数组返回
不改变原数组
传参:指定要提取嵌套数组的结构深度,默认为1
const arr1 = [0, 1, 2, [3, 4]];
console.log(arr1.flat());
// expected output: [0, 1, 2, 3, 4]
const arr2 = [0, 1, 2, [[[3, 4]]]];
console.log(arr2.flat(2));
// expected output: [0, 1, 2, [3, 4]]
//使用 Infinity,可展开任意深度的嵌套数组
var arr4 = [1, 2, [3, 4, [5, 6, [7, 8, [9, 10]]]]];
arr4.flat(Infinity);
// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// 扁平化数组空项,如果原数组有空位,flat()方法会跳过空位
var arr4 = [1, 2, , 4, 5];
arr4.flat();
// [1, 2, 4, 5]
改变原数组的方法:
push() pop() shift() unshift()
reserve()
sort()
splice()
fill()
copyWithin()
不改变:
concat()
filter()
flat()
7.对AJAX的理解
8.尾调用
指函数的最后一步调用另一个函数
ES6中尾调用优化只在严格模式下开启
代码执行基于执行栈,在一个函数中调用另一个函数时,会保留当前的执行上下文,再新建另一个执行上下文加入栈中
使用尾调用,可以不必保留当前的执行上下文,节省了内存
9.常见的DOM操作
①DOM节点的获取
var imooc=document.getElementById('imooc') //按id查询
var pList=document.getElementByTagName('p') //按标签名查询
var moocList=document.getElementsByClassName('mooc')
//按类名查询
var pList=document.querySelectorAll('.mooc')
//按css选择器查询
②DOM节点的创建
已知HTML结构:
<div id="container">
<h1 id="tiitle">我是标题</h1>
</div>
添加一个有内容的span节点到id为title的节点后面:
var container=document.getElementById('container')
var targetSpan=document.createElement('span')
targetSpan.innerHTML='hello world'
container.appendChild(targetSpan)
③DOM节点的删除
删除id为title的元素
var container=document.getElementById('container')
var targetNode=document.getElementById('title')
container.removeChild(targetNode)
④修改DOM元素
交换两个DOM元素的位置
var title=document.getElementById('title')
var content=document.getElementById('content')
container.insertBefore(content,title)
10.use strict模式
禁止使用with语句
禁止this关键字指向全局对象
对象不能有重名的属性
目的:
消除js语法的不合理不严谨之处
消除代码运行的不安全之处
11.forEach和map方法的区别
都是用来遍历数组的
forEach():
针对每一个元素执行提供的函数,对数据的操作会改变原数组,没有返回值
map():
不改变原数组,返回一个新数组,为原数组调用函数处理之后的值
12.原型与原型链
13.arguments
函数里的一个内建对象,包含了函数接收到的所有变量
是类数组
在实际开发中,可以使用arguments获取到所有实参
遍历接收的实参:
for(let i = 0; i <arguments.length;i++){
console.log(arguments[i]);
}
14.函数柯里化
只传递给函数一部分参数来调用它,让它返回一个函数去处理剩下的参数
简单实现add(1)(2)(3):
const add = x => y => z => x + y + z;
console.log(add(1)(2)(3));
如果被要求实现add函数同时支持:
add(1, 2, 3);
add(1, 2)(3);
add(1)(2, 3);
可以自己实现一个工具函数专门生成柯里化函数:
const curry = (fn, ...args) =>
// 函数的参数个数可以直接通过函数数的.length属性来访问
args.length >= fn.length // 这个判断很关键!!!
// 传入的参数大于等于原始函数fn的参数个数,则直接执行该函数
? fn(...args)
/**
* 传入的参数小于原始函数fn的参数个数时
* 则继续对当前函数进行柯里化,返回一个接受所有参数(当前参数和剩余参数) 的函数
*/
: (..._args) => curry(fn, ...args, ..._args);
function add1(x, y, z) {
return x + y + z;
}
const add = curry(add1);
console.log(add(1)(2, 3));