2020-10-13
常用浏览器
- webkit内核(V8引擎)
- 谷歌 Chrome
- Safari
- Opera >= V14
- 国产浏览器
- 手机浏览器
- Gecko
- 火狐firefox
- Presto
- Opera < V14
- Trident
- IE
- IE Edge 开始采用双内核(包含chrome mini)
JS做客户端语言
按照相关的js语法,去操作页面中的元素,有时还需要操作浏览器里面的一些功能
- ECMAScript3/5/6…:JS的语法规范(变量、数据类型、操作语句等等)
- DOM(document object model)文档对象模型,提供一些JS的属性和方法,用来操作页面中的DOM元素
- BOM(broswer object model)浏览器对象模型,提供一些JS的属性和方法,用来操作浏览器
JS中的变量 variable
变量: 可变的量,在编程语言中,变量其实就是一个名字,用来存储和代表不同值的东西。
// 创建变量的几种方式
// ES3
var a = 12;
console.log(a); //=>输出的是a代表的值12
// ES6
let b = 100;
b = 200;
//常量
const c = 1000;
c = 2000; //=>报错,常量的值不能被修改
// 创建函数也相当于创建变量
function fn(){}
//创建类也相当于创建变量
class A{}
//ES6的模块导入也相当于创建变量
import B from 'b.js';
//Symbol 创建唯一值
Symbol c = 100;
JS中的命名规范
- 严格区分大小写
- 使用数字、字母、下划线$,不能以数字开头
- 使用驼峰命名法:首字母小写,其余每一个有意义单词的首字母大写(命名尽可能语义化明显,使用英文单词)
- 不能使用关键字和保留字(当下有特殊含义的是关键字,未来可能成为关键字的叫保留字)
JS中常用的数据类型
- 基本数据类型
- 数字 number (常规数字和NaN)
- 字符串 string 所有单引号、双引号和反引号包起来的都是字符串
- 布尔 boolean true/false
- 空对象指针 null
- 未定义 undefined
- 引用数据类型
- 对象数据类型 object
- {} 普通对象
- [] 数组对象
- /^$/ 正则对象
- Math 数学函数对象
- 日期对象 Date
- …
- 函数数据类型 function
- 对象数据类型 object
number 数字类型
包含:常规数字和NaN
NaN
not a number:不是一个数,但它隶属于数字类型
NaN和任何值(包括自己)都不相等: NaN != NaN, 所以不能用双等号的方式判断是否为有效数字
isNaN
检测一个值是否为非有效数字,如果不是有效数字返回true,反之返回false
在使用isNaN进行检测的时候,首先会验证检测的值是否为数字类型,如果不是先基于Number()方法,把值转换为数字类型,然后再检测。
// isNaN([val])
console.log(isNaN(10)); //false
console.log(isNaN('AA')); //true
console.log(isNaN('10')); //false
把其它类型值转换为数字类型
- Number([val])
- 把字符串转换为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变为零
console.log(Number('12.5'))// 12.5 console.log(Number('12.5px'))// NaN console.log(Number('12.5.5'))// NaN console.log(Number(''))// 0
- 布尔值转换为数字 true是1 false是0
console.log(true); //1 console.log(false); //0 console.log(isNaN(false)); //false 因为false会被转换为数字 console.log(isNaN(true)); //false 因为true会被转换为数字
- null 和undefined 转换为数字类型 null -> 0 undefined -> NaN
console.log(Number(null)); //0 console.log(Number(undefined)); //NaN
- 把引用数据类型转换为数字,是先把它基于toString方法转换为字符串,然后再转换为数字
console.log(Number({name: '10'})); //NaN console.log(Number({})); //NaN console.log(Number([])); //0 console.log(Number([10])); //10 console.log(Number([10, 20])); //NaN
- 把字符串转换为数字,只要字符串中包含任意一个非有效数字字符(第一个点除外)结果都是NaN,空字符串会变为零
- parseInt/parseFloat([val], [进制]):转换为数字的方法,对于字符串,是从左到右依次查找有效数字字符,直到遇到非有效数字后停止,不管后面是否还有有效数字都不再找了,然后把找到的当数字返回
parseInt/parseFloat是用来处理字符串的,所以如果遇到其它类型也要先转换为字符串然后再转数字let str = '12.5px'; console.log(Number(str)); //NaN console.log(parseInt(str)); //12 console.log(parseFloat(str)); //12.5 console.log(parseFloat('width:12.5px')); //NaN
- == 进行比较时可能出现要把其它类型值转换为数字
string字符串数据类型
所有用单引号、双引号、反引号(ES6模板字符串)包起来的都是字符串
把其它类型值转换为字符串
- [val].toString()
null 和 undefined是禁止直接使用toString的
null.toString(); //会报错,但是和undefined一样转换为字符串的结果就是‘null’/‘undefined’
普通对象.toString()的结果是’[object Object]’,原因是Object.prototype.toString方法不是转换为字符串的而是用来检测数据类型的let a = 12; console.log(a.toString()); //'12' console.log((NaN).toString()); //'NaN' console.log({name:'10'}.toString()); //'[object Object]'
- 字符串拼接
在四则运算中,除加法之外,其余都是数学运算,只有加法可能存在字符串拼接(一旦遇到字符串则不是数学运算而是字符串拼接)
console.log('10' + 10); //'1010' console.log('10' - 10); //0 console.log('10px' - 10); //NaN
boolean 布尔数据类型
只有两个值true/false
把其它类型转换为boolean值
只有0、NaN、‘’、null、undefined五个之转换布尔值为false,其余的都为true(没有任何特殊情况)
- Boolean([val])
console.log(Boolean(0));// false
console.log(Boolean(''));// false
console.log(Boolean(' '));// true
console.log(Boolean(null));// false
console.log(Boolean(undefined));// false
console.log(Boolean([]));// true
console.log(Boolean([12]));// true
- !/!!
// !:取反(先转布尔,再取反)
console.log(!1);//false
//!!:取反再取反,转换为布尔相当于Boolean
console.log(!!1);//true
- 条件判断
//如果条件只是一个值,不是==或===或!=等这些比较,是要把这个值先转换为布尔然后验证真假
if(1){}
null / undefined
null 和 undefined都代表没有
- null:意料之中,一般都是开始不知道值,我们手动设置为null,后期再赋值
let num = null;//不占用内存空间
//....
num = 100;
- undefined:意料之外
let num;//创建一个变量没有赋值,默认值是undefined
对象数据类型 - 普通对象
{[key]:[value],…}任何一个对象都是由零到多组键值对(属性名:属性值)组成的且属性名不能重复,属性名是数字或字符串格式。
删除属性
delete 对象名.属性名,把属性彻底删除
对象名.属性名 = null; 属性还在,值为空
2020-10-14
堆栈底层机制
JS中的数据类型检测
- typeof [val]:用来检测数据类型的**运算符**
- 基于typeof检测出来的结果首先是一个字符串,字符串中包含对应的类型
- 局限性:typeof null => “object” 但是null并不是对象类型
- 基于typeof无法细分出当前值是普通对象还是数组对象等,因为只要是对象数据类型,返回的结果都是"object"
- instanceof:用来检测当前实例是否隶属于某个类
- constructor:基于构造函数检测数据类型(也是基于类的方式)
- Object.prototype.toString.call():检测数据类型最好的办法
匿名函数
匿名函数表达式:把一个匿名函数本身作为值赋值个其它东西,这种函数一般不是手动触发执行,而是靠其它程序驱动触发执行(如:触发某个事件的时候执行)
2020-10-16
浏览器的常用输出方式
- console.log/dir/table…:控制台输出
- console.log:在控制台输出信息
- console.dir:输出一个对象的详细键值对信息
- console.table:把一个多维JSON数组在控制台按照表格的方式输出
- 浏览器弹出窗口 alert/confirm/prompt
- 三种方式输出的结果都必先经过toString转换为字符串
- 三种方式都会阻断JS代码执行,只有窗口关掉JS才会继续执行
- document.write在页面中写入信息,输出结果都是字符串
2020-10-19
== VS ===
==: 相等,数据类型不同,先转换为一样的再比较
===: 绝对相等,必须类型和值都相同才返回TRUE,(switch判断中,)
每一种case的值比较都是基于“三个等号”来完成的
let a = '10';
a = a + 1 => '101'
a += 1 => '101'
a++ => 11 //a++和以上两种完全不一样,它是纯粹的数学运算
let b = '10'
switch(b){
case 10:
b++;
break;
default:
b--;
break;
}
console.log(b); // 9
数据类型基础知识变态练习题
!(!"Number(undefined)") //true
isNaN(parseInt(new Date())) + Number([1]) + typeof undefined;//'2undifined'
Boolean(Number("")) + !isNaN(Number(null)) + Boolean("parseInt([])") + typeof !(null);// '2boolean'
parseFloat("1.6px") + parseInt("1.2px") + typeof parseInt(null); //'2.6number'
isNaN(Number(!!Number(parseInt("0.8")))); //false
console.log(1 + "2" + "2");//'122'
!typeof parseFloat('0');// false
Number("");//0
typeof "parseInt(null)" + 12 + !!Number(NaN); // 'string12false'
!typeof (isNaN("")) + parseInt(NaN); //NaN
typeof !parseInt(null) + !isNaN(null);//'booleantrue'
2020-10-20
函数执行的底层原理
创建函数开辟的堆内存中存储的是函数体中的代码,但是是按照字符串存储的
每一次函数执行的目的都是把函数体中的代码(先从字符串变为代码)执行
每次执行都会形成一个全新的私有栈内存
arguments函数内置的实参集合
- 类数组集合,集合中存储着函数执行时传递的所有实参信息
- 不论是否设置形参,arguments都存在
- 不论是否传递实参,arguments也都存在
- arguments.callee:存储的是当前函数本身(一般不用,JS严格模式下禁止使用这些属性)
//arguments 任意数求和案例
function sum(){
let total = null;
for(let i = 0; i < arguments.length; i++){
let item = Number(arguments[i]);
if(isNaN(item)){
continue;
}
total += item;
}
return total;
}
let result = sum(10, 20, 30, 40);
console.log(result); //100
result = sum(19,20);//39
console.log(result);
result = sum(10, 'aa');//10
console.log(result);
箭头函数 arrow function
- 如何函数中只有一行RETURN,则可以省略RETURN和大括号,多行不可以。
- 如果只有一个形参则小括号可以直接省略
- 箭头函数中没有arguments,但可以用…变量名代替(…剩余运算符)
function sum(n, m){
return n + m;
}
//=>
let result = (n, m) => n + m;
function fn(n){
return function(m){
return n + m;
}
}
//=>
let fn = n => m => n + m;
2020-10-21
Math数学函数
- Math.abs([number value]):获取一个数的绝对值,如果传入的不是数字类型则会用Number转换为数字
- Math.ceil/floor([number value]):向上/向下取整
- Math.round([number value]):四舍五入(正数中.5要进,负数中.5要舍)
- Math.max([val1],[val2],…)/min([val1],[val2],…):获取一堆数最大值和最小值
- Math.sqrt/pow():给一个数字开平方/求一个数的多少次幂
- Math.random():获取0~1间的随机小数
- Math.round(Math.random()*(m-n)+n) 获取n~m间的随机整数,包含n和m
JS中数组常用方法剖析
- 方法的作用和含义
- 方法的实参(类型和含义)
- 方法的返回值
- 原来的数组是否会发生改变
1. 实现数组增删改的方法
原来数组会改变
push
push: 向数组末尾增加内容
@params:多个任意类型
@return:新增后数组的长度
let arr = [10,20];
let len = arr.push(30, 'AA', {name:'array'});
console.log(len, arr);
unshift
unshift: 向数组开始增加内容
@params:多个任意类型
@return:新增后数组的长度
shift
shift: 删除数组中的第一项
@params
@return:删除的那一项
pop
shift: 删除数组中的最后一项
@params
@return:删除的那一项
基于原生js让数组长度变小也可以删除数组后面的项
let arr = [1,2,3];
arr.length--;//删除最后一项
splice
splice: 实现数组的删除
@params:
n,m都是数字,从索引n开始删除m个元素,m不写默认删除到数组末尾,如果只传个0则清空数组
@return:把删除的部分用新数组存储来返回
//删除最后一项
arr.splice(arr.length-1);
//删除第一项
arr.splice(0,1)
splice
splice: 实现数组的增加、修改
@params:
n,m, x 从索引n开始删除m个元素,用x占用删除的部分
n,0, x 从索引n开始一个都不删除,把x放到索引n的前面
@return:把删除的部分用新数组存储来返回
//向数组末尾追加
arr.splice(arr.length, 0, 'aaa');
//向数组kais开始追加
arr.splice(0, 0, 'bbb');
2. 数组的查询和拼接
原来数组不会改变
slice
slice:实现数组的查询
@params:n,m都是数字,从索引n开始,找到索引为m的地方(不包含m这项),如果m不传则找到末尾。若n为0,m不传则可以实现数组的克隆。
@return: 把找到的内容以一个新数组形式返回
let arr = [1,2,3,4,5,6];
let res = arr.slice(1, 3);
console.log(res); // 2, 3
//关于n和m的一些特殊情况
//1. n/m为负数
arr.slice(-1);//从数组的末尾开始取1个元素
arr.slice(-1,-5);//返回空数组,因为n>m
arr.slice(-5,-1);//n和m都为负数则从数组末尾开始算索引,最后一项为-1,倒数第二项为-2,以此类推。返回[2,3,4]
arr.slice(-1,3);//n<0,m>0返回空数组
arr.slice(1,-2);//m<-1则从n开始查到数组末尾返回[2,3,4,5,6]
arr.slice(-1,1);//n<0,m>0 返回空数组
//2. n,m均为正数且n>m
arr.slice(5,3);//返回空数组
//3. n或m为小数
arr.slice(0.5,3);//小数向下取整,返回[1,2,3]
arr.slice(0.5,0.8);//向下取整,返回空数组
arr.slice(0.5,1.8);//返回[1]
//4. n或m为非有效数字
arr.slice('sd',3);//若n为非有效数字,则从索引0开始,返回[1,2,3]
arr.slice('sd','sadf');//若m为非有效数字则返回空,不管n是否是有效数字
arr.slice('3','sadf');//若m为非有效数字则返回空,不管n是否是有效数字
arr.slice(3,'sadf');//若m为非有效数字则返回空,不管n是否是有效数字
//5. n或m大于数组长度
arr.slice(3,10);//若m大于数组长度,则找到数组末尾
arr.slice(10,3);//若n大于数组长度则返回空数组
concat
concat:实现数组的拼接
@params:多个任意值
@return: 返回拼接后的新数组,原数组不变
let arr = [1,2,3];
lert arr2 = [4,5,6];
let res = arr.concat(arr2);
console.log(res);//[1,2,3,4,5,6]
3. 把数组转换为字符串
原来数组不会改变
toString
toString:把数组转换为字符串
@params
@return:转换后的字符串,原数组不变
join
join:把数组转换为字符串
@params:指定的分隔符(字符串格式),不指定默认为逗号
@return:转换后的字符串,原数组不变
arr.join(’;’);
4. 检测数组是否包含某一项
原来数组不会改变
indexOf / lastIndexOf / includes
indexOf / lastIndexOf:检测当前项在数组中第一次/最后一次出现的索引值
@params:要检索的这一项的内容
@return:返回这一项出现的位置索引值(数字),如果没有返回-1,有则返回索引值
5. 数组的排序或排列
reverse
reverse:把数组倒过来排列
@params
@return:排列后的新数组,原数组不变
sort
reverse:实现数组的排序
@params:可以没有也可以是函数
@return:返回排序后的新数组,原数组改变。
如果不传递参数,是无法处理10以上的数字按大小排序的(默认是按每一项第一个字符来排序)
可以传递一个函数作为参数
let arr = [10,22, 5, 1, 23,40];
arr.sort((a,b)=>{
return a - b;//正序
return b - a;//倒序
});
6. 遍历数组中每一项的方法
forEach
map
filter
find
reduce
some
every
详见:JavaScript数据类型 - Array类型
6. 数组去重*
- 创建一个新的空数组,然后遍历原数组把遍历的元素添加到新数组中,添加前需判断新数组中是否已经存在该元素,如果不存在则添加
- 用两个for循环遍历原数组,用当前项跟它后面的没一项进行对比,如果相等则删除(这里需要注意:因为操作的是同一个数组,删除元素时长度会发生变化,所以会引起数组塌陷问题)
- 创建一个空对象,循环数组,把数组的元素作为对象的键和值存入对象,存入前需判断该属性是否存在,不存在则添加,如果存在则把元素从数组中删除。
- 基于ES6的Set去重
基于splice删除性能不好,当前项删除,后面每一项都要向前提一位,如果内容过多会影响性能。可以用最后一项替换当前项,然后删除最后一项的方式来删除
let arr = [1,2,3,2,2,1,3,3,2,1,1,2,4];
//方式一:创建新数组
let newArr = [];
for(let i = 0; i < arr.length; i++){
if(newArr.includes(arr[i])) continue;
newArr.push(arr[i]);
}
//方式二:删除数组元素
for(let i = 0; i < arr.length; i++){
for(let j = i + 1; j < arr.length; j++){
if(arr[i] === arr[j]){
arr.splice(j, 1);
//删除后需要j--,避免数组塌陷
j--;
}
}
}
//方式三:创建空对象
let obj = {}
for(let i = 0; i < arr.length; i++){
let item = arr[i];
if(!obj[item]){//属性不存在
//arr.splice(i, 1);
//删除后需要j--,避免数组塌陷
//可以用最后一项替换当前项,然后删除最后一项的方式来删除,性能比splice要好
arr[i] = arr[arr.length-1];
arr.length--;//删除最后一项
//i--仍然需要,因为最后一项的值替换过来也要重新判断的。
i--;
continue;
}
obj[item] = item;
}
//方式四:new Set
arr = [...new Set(arr)]