浏览器内核
现在是多服务器共存,数据服务器,web服务器
- webkit内核(V8引擎)
- 谷歌Chrome
- Safari
- Opera 14+
- 国产浏览器
- 手机浏览器…
- Gecko
- 火狐Firefox
- Presto
- Opera 14-
- Trident
- IE
- IE edge双内核(包含Chromium)
- 谷歌浏览器开发者工具
- Elements:查看结构样式
- Console:查看输出结果和报错信息
- Network:查看当前网站所有资源的请求信息(包括和服务器传输的HTTP报文信息),加载时间(根据加载时间进行项目优化)
- Sources:查看源码
- Application:Manifest(H5离线缓存技术),网站的数据存储和资源文件
JS基本笔记
- 定义方式:var/let/const/function/import/class
代码块
//ES3
var i = 1;
//ES6
let b = 100;
const c = 100;//定义常量,可修改属性
//创建函数和创建类相当与创建变量
function fn(){}
class A{}
//模块导入
import B from 'B.js'
//Symbol创建唯一值
let C = Symbol(100);
let D = Symbol(100);
C != D;
JS常用数据类型
- 基本数据类型
-
数字number:
- 常规数字
- NAN
(NAN和任何值都不相等,包括NAN != NAN,不能使用相等方式判断),使用isNAN(val)判断是否为有效数字
-
字符串string:
用单引号,双引号,反引号(ES6模板字符串)包起来的 -
布尔boolean:
true/false -
空对象指针null
-
未定义undefined,未赋值
-
- 引用数据类型
- 对象数据类型object
- {} 普通对象(可多维)
- [] 数组对象(可多维)
- /^[±}?(\d|([1-9]\d+))(.\d+)?$/正则对象
- Math对象
- 日期对象
- 函数数据类型function
- 对象数据类型object
Number类型:
isNAN():
- 首先会验证值是否为数字类型,如果不是,把值经过Number()方法转化为数字类型,再检测。(如:isNAN(‘10’) 为false,isNAN(10)为false都是有效数字);
- Number(‘SS’) => NAN, isNAN(NAN) => true
Number():
- 把基本数据类型转化为数字类型(只要字符串中包含任意一个非有效数字字符(第一个点除外),结果都是NAN,空字符串变成0),底层渲染规则:
console.log(Number('12.5')); => 12.5
console.log(Number('12.5px')); => NaN
console.log(Number('12.5.5')); => NaN
console.log(Number(' ')); => 0
console.log(Number(true)); => 1
console.log(Number(false)); => 0
console.log(Number(null)); => 0
console.log(Number(undefined)); => NaN undefined未赋值
- 把引用数据类型转化为数字,先经过toString(),然后转化为数字
{}.toString() => 'object'
{name:'9'}.toString() => 'object'
[].toString => ''
[12].toString => '12'
[12, 23].toString => '12, 23'
parseInt()/parseFloat([val], [进制]):
- 对于字符串,从左往右查找数字字符,首字符需为有效数字字符,否则停止查找,parseInt()不识别小数,为单独方法规则和Number()机制不一样
- 输入其他时,会把输入的值转化为字符串
==进行比较时,可能会把其他类型转化为数字类型
String类型:
把其他类型转化为字符串
- [val].toString()
//不能直接toString()
(val).toString();
//null,undefined禁止使用toString(),但是能转化为字符串的结果
({name:'xx'}).toString(); =>'[object Object]' => Object.prototype.toString方法是用来检测数据类型
- 字符串拼接
- 加号相连(四则运算中,只有+遇到字符串才会拼接字符串其他的都为数学运算,遇到元素会先Number()方法转换,然后先计算)
'10' + 10 => '1010' '10' - 10 => 0 '10px' - 10 => NAN //先经过Number('10px')转化 10 + null + true + [] + undefined + 'jj' + null + [] + 10 + false; /* * 10 + null => 10 + 0 = 10 * 10 + true => 10 + 1 =11 * 11 + [] => 11 + '' = '11' * '11undefinedjjnull10false' * */
- eval() 函数可计算某个字符串,并执行其中的的 JavaScript 代码。
boolean类型
true/false
把其他值转换为boolean
-
只有0、NAN, ‘’, null, undefined转换为false, 其他为true
-
Boolean([val])
-
!(取反)/!!(两次取反)
-
条件判断(如果不是==/===/!=/>=等比较,先把值转化为布尔值),(特别null == undefined 为true)
Boolean([]);//true
Boolean(' ');//true 有空格不是空字符串
null / undefined
都代表没有
- null: 开始不知道值,未来需要使用的变量,后面赋值,赋值null不占据内存
- undefined: 浏览器判断,创建变量未赋值
object对象
普通对象
{[key]: [value]}键值对形式,属性名不能重复,属性名只能是数字或字符串格式等基本数据类型(null, undefined, NaN等不需加引号,也可调用;属性名不存在是undefined, 其他形式会转化为字符串);属性值如果是变量,把变量存储值拿过来作为属性值,只能放值,最后都会转化为值。
let person = {name: '555', 1:100};
//获取属性
person.name
person['name']
//数字属性名,只能用中括号方式查找
person[1] => 100
person.1 => SyntaxError:语法错误
person.GD = 'ss'; => 添加属性
//属性和变量的区别
let name = 10;
let obj = {
name: '999',
};
obj.name => '999'
obj['name'] => '999'
obj[name] => name是变量, obj[name变量代表的值], 相当于obj[8] => undefined
//假删除
person.name = null;
//真删除
delete person[1];
delete person['name'];
delete person.name;
数组对象
特殊对象数据类型
- 设置的是属性值,属性名是默认生成的数字,从0开始称为索引,代表每个位置的数字属性名,默认属性名length存储数组长度;
//获取数组长度
per.length;
per['length']
//追加内容,arr长度自动增加
arr[arr.length] = 100;
数据类型检测
- typeof 运算符(辨别不出null类型,普通对象还是数组对象等,返回皆为’object’)
typeof 1 => 输出结果是字符串'number' //局限性 typeof null => 'object' null不是对象 console.log(typeof typeof typeof []) => 'string'//先检测靠近值的,两个以上的typeof检测都为'string'
- instanceof 检测实例是否属于某个类
- constructor 基于构造函数检测数据类型(基于类的方法)
- Object.prototype.toString().call() 检测数据类型最好的方法
判断语句
if/else if/else
- if(条件){} else{}
- if(条件){} else if(条件1){} else{}
- if(条件){} else if(条件1){}
三元运算符:条件 ? true : false
- 处理的事情多可用括号包起来,每件事用逗号隔开
- 如果不需要处理事情,可以用null/undefined(void:0)占位
- 简单的if/else语句才使用
if(a > 0 && a < 10){
a++;
console.log(a);
}
等价于
a > 0 && a < 10 ? (a++, console.log(a)) : null;
switch case
- 一个变量在不同值的情况下的不同操作
- 每一个case结束,加上break
- default等价于else
== && ===
- ==:相等(左右两边的数据类型不一样,默认转化为相同类型再比较)
- ===:绝对相等(类型不等一定不等,不会默认转换数据类型),为了业务的严谨推荐使用
循环语句
- 创建循环初始值
- 验证循环执行条件
- 条件成立执行循环体内容
- 当前循环结束执行累计操作
- continue结束当前循环
- break强制结束整个循环
for循环
for-in
循环遍历对象的键值对(continue和break同样可用),循环次数为对象中的键值对(除非break结束)
for(let 变量(key) in 对象)
for (const key in obj) {
//优先遍历数字属性,从小到大
//每次循环key变量存储的值:当前对象的属性名
//获取属性值:obj[属性名] => obj[key] key是把属性名放入的变量
}
for-of(ES6)
while
do-while
//JS代码加载完成才能看到页面,用户才能点击,因为事件点击才能触发,所以循环体已经遍历完了,最后在函数体获得的i为3
在函数体里面获取索引值:
1. 使用元素自定义属性获取索引
for (var i = 0; i < 3; i++) {
//=> 1. liActive[i].index = i;
liActive[i].onclick = function(){
//函数体
//console.log(i); => 不可
console.log(this.index); => 可以
}
}
2. 闭包
for (var i = 0; i < 3; i++) {
liActive[i].onclick = (function(i){
return function(){
console.log(i); => 可
}
})(i)
}
3. ES6
for (let i = 0; i < 3; i++) {
liActive[i].onclick = function(){
console.log(i); => 可以
}
}
函数function
函数就是一个方法体,函数就是实现某个功能的代码放在一起进行封装,需要时执行:减少页面中的冗余代码,提高代码重复使用率(低耦合高内聚), 函数不调用无意义,就是一个堆
- 创建函数
- 形参
- 返回值
- 执行函数
- 实参
- arguments
- 函数底层运行机制
- 每次函数执行的目的都是把函数体中的代码(先从堆里嘛的字符串变成代码),执行 => 形成一个新的私有栈内存
- …
创建函数
//=> ES5老版本,函数有形参无实参,默认未传入的实参为undefined
function [函数名]([形参变量1], ....){
//函数体:基于JS完成需要实现的功能
return [处理结果];
}
//一般不传参,做形参默认值处理
function sum(n, m) {
if(n === undefined){//null == undefined为true, ==不严谨
n = 0;
}
if(typeof m == 'undefined'){
m = 0;
}
let res = n + m;
console.log(n, m, res);
}
sum(10, 20); => n为10, m为20, res为30
sum(, 30); => 不成立
sum(12); => n为12, m为undefined, res为NaN
[函数名]([实参1], ...);
ES6箭头函数(arrow function)
简单, 没有arguments
function sum(n, m){
return n+m;
}
let sum = (n, m) => {
return n+m;
};
//如果函数体里只有一行return 可以省略return和大括号
let sum = (n, m) => n+m
function fn(n){
return function(m){
return n + m;
}
}
let fn = n => m => n + m;
//n和m不传值
function sum(n, m){
if(typeof n == 'undefined'){
n = 0;
}
if(typeof m == 'undefined'){
m = 0;
}
return n+m;
}
let sum = (n = 0, m = 0) => n + m;
//无arguments,用arg(纯数组,比arguments更好)剩余运算符代替获取传递实参集合
let sum = (...arg) => eval(arg.join('+');//任意数求和
函数的返回值
return
- 函数执行时,函数体内部的变量外部无法获取,如果想要获取内部信息,需要基于return返回值机制,把信息返回,无return默认返回值是undefined
- 函数体中有return后面代码不执行
控制台输出console.log(1), 先打印1, 再输出undefined(log()函数无返回值)
匿名函数
- 函数表达式:把匿名函数本身作为值赋值给其他东西,一般不是手动触发执行,而是靠其他程序触发执行(例如:原始点击事件)
dom.onclick = function(){}
setTimeout(function(){}, 1000);
- 自执行函数,创建完一个匿名函数,立刻加小括号执行
(function (n){})();
arguments函数内置的实参集合
- 类数组集合,集合存储着所有函数执行时,传递的实参信息
- 不论是否设置形参,arguments都存在
- 不论是否传递实参,arguments都存在
- arguments.callee: 存储的是当前函数本身(一般不用,JS严格模式下禁止使用)
任意数求和 - 传递实参个数不定
- 传递值可为任何值
++ && –
- a++, a–
let a = '10';
//字符串拼接
i = i + 1; => '10' + 1 => '101'
i+=1 => '101'
//纯粹的数学运算
i++ => i=11
let i = 1;
5+(i++) => 5+1, 后自加
- ++a, --a
5+(++i) => 5+2, 先进行自加, 后计算
Math对象(数学函数)
对象中存储很多操作数字的属性方法,被称为数学函数
typeof Math => 'object'
Math = {
abs : function(){
[native code]//原生函数,不允许看
},
}
Math常用的属性和方法
- Math.abs([number val])获取绝对值,传递的不是数字类型的值,先基于Number()转化为数字处理
- Math.ceil/floor([number val]); 向上取整/向下取整,无小数取整数
- Math.round([number val]); 四舍五入(不分正负数),正数里面.5属于入,负数数里面.5属于舍
- Math.max/min([val1], [val2]…); 传多值获取最大值,最小值
Math.max([2, 21, 432]); => 转化为NaN,此处只传数组
- Math.sqrt/pow(); 开平方(n)/多少次幂(n, m)n的m次方 Math.pow(2, 10) => 1024
- Math.random(); 获取一个0~1随机数
//获取n~m的随机数 Math.round(Math.random() * (m - n) + n); Math.floor(Math.random() * m) + n;
数组对象
数组常用的方法
- 方法的作用和含义
- 方法的实参(类型和含义)
- 方法的返回值
- 原来的数组是否会改变
- 实现数组增删改方法
- 会修改原来的数组
- push() //向数组末尾增加内容,@params’参数’(数值类型多种任意类型),@return 新增后的数组长度,还可ary[ary.length]赋值添加新元素,可传多值
- unshift()//向数组开始位置增加内容,@params’参数’(数值类型多种任意类型),@return 新增后的数组长度,可传多值
- shift()//向数组开始位置删除内容,@return 删除内容,不能使用对象方式删除,可以删除某一项的内容,但是不会影响length和数组本身的结构
- pop()//向数组最后位置删除内容,@return 删除内容,可用ary.length–;让数组长度减少默认减少最后一位
- splice()//实现数组的增删改,
- @params
- n, m 都是数字 从索引n开始删除m个元素(m不写,一直删除到末尾)
-
- n, m, x 从索引n开始删除m个元素,用x占用删除的部分
- n, 0, x 从索引n开始,一个都不删,把x放到索引n的前面
- @return
- 把删除的部分用新数组存储起来
- @params
- 数组的查询和拼接(原来的数组不会变)
- slice()//查询,@params n, m 都是数字,从索引n开始,找到索引为m的地方,@return 找到的内容以新数组形式返回
- concat//数组拼接,新数组向后添加,@params 多个任意值,@return 拼接后新数组
- join()//把数组转化为字符串,toString方法一样,但是可以指定分隔符,@params 指定分隔符(字符串形式),@return 转化后的字符串(原来数组不变)
- 检测数组中是否包含某一项
- indexOf/lastIndexOf//检测当前项在数组中第一次或者最后一次出现位置的索引值,@params要检索的这一项内容,@return 这一项的位置索引(数字),如果数组中没有这一项,返回结果是-1
- includes()//ES6判断方法,返回值true/false
- 数组排序(数组改变)
-
reverse//把数组倒过来排列,@return 排列后的新数组
-
sort//把数组从小到大排序,@params 可有可无 ,@return 排序后的新数组默认不传参,无法处理10以上的数字排序
//重写sort();
sort((a, b) => a - b);
- 遍历数组每一项的方法
- forEach()
arr.forEach((item, index) => { })
- map()
- filter
- find
- reduce
- some
- every
- …
- forEach()
数组去重
- 比较LOW
- 创建一个新的空数组,循环获取数组的每一项添加到新数组中,但是每次循环需要验证
- forEach()
let newArr = []; arr.forEach(item => { if(newArr.includes(item)) return; newArr.push(item); })
- 循环数组每一项,拿每一项数值和后面的每一项比较,遇到相同的,用splice删除
//数组塌陷问题, length减少跳到下一个元素删除,解决方法,为了不让i累加先i-- for(let i = 0; i < arr.length; i++){ let item = arr[i]; for(let j = i + 1; j < arr.length; j++){ let compare = arr[j]; if(compare === item){ arr.splice(j, 1); j--;//=>解决数组塌陷 } } }//=>实现不了 let newArr = []; arr.forEach(item => { if(newArr.includes(item)) return; newArr.push(item); }) //=>基于splice删除性能不好,当前项被删后,后面每一项的索引要提前一位,内容过多会影响性能
- 基于对象去重,把数值存进对象作为属性名和属性值,(obj[val] === val 判断)
//比较好的方法 let obj = {}; for (let i = 0; i < arr.length; i++) { let item = arr[i]; if (obj[item] !== undefined) { arr[i] = arr[arr.length - 1];//把最后的值调到替换的元素,优化splice的性能 arr.length--; arr.splice(j, 1); i--; //=>解决数组塌陷 continue } obj[item] = item; }
- 其他去重
ary = [...new Set(ary)];
字符串
按值操作不像数组引用类型
字符串常用方法
- 每一个字符串都是从0到1组成,str.length字符串长度,获取第一个字符str[0]和获取数组元素一样,str[10000]为undefined不存在这个索引,可用循环
- charAt(根据索引获取指定位置的字符) / charCodeAt(获取指定字符的ASII码值), @params n[number]获取字符的索引,@return 返回查找的字符找不到返回的空字符不是undefined,或者编码值
- substr / substring / slice 截取字符串
- substr(n, m): 从索引n开始截取m个字符,m不写截取到末尾
- substing(n, m): 从索引n开始找到索引为m处,超过索引也是截取到末尾
- slice(n, m): 和substring一样,都是找到索引为m处,但是slice可以支持负数作为索引(str.length + 负索引)
- indexOf / lastIndexOf 验证字符串是否存在
- indexOf(x, y): 获取x第一次出现位置的索引,y是控制查找起始位置索引
- lastIndexOf(): 最后一次出现位置的索引,没有字符,返回结果是-1
- includes()
- toUpperCase / toLowerCase 大小写转化
- split([分隔符]): 把字符串按指定的分隔符拆分成数组(和数组的join对应)
- replace(新字符, 老字符): 实现字符串替换,不使用正则表达式只能替换一次, 正则(str.replace(/新字符/g, 老字符)
实现一些常用需求
- 时间字符串处理
- replace
- indexOf获取指定符号索引,使用substring分割字符串
- 基于spllit拆分
let time = '2019-1-20 12:45:00'; let arr = time.split(/(?: |-|:)/g);//=>['2019','1','20','12','45','00']
- 实现queryURLParameter获取URL地址问号后面传递的参数
- indexOf
日期对象
日期对象的基本操作
let time = new Date();
/*
* 获取当前客户端的时间
* Tue Nov 26 2019 15:35:46 GMT+0800 (中国标准时间)
* 获取的不是字符串是对象数据类型的,属于日期对象
*/
标准日期对象提供属性和方法操作日期信息
- getFullYear() 年
- getMonth() 月 0~11 => 1月到12月
- getDate() 日
- getHours()时
- getDay()星期 0~6 => 周日到周六
- getMinutes()分
- getSeconds()秒
- getMilliseconeds()毫秒
- getTime()当前日期距离1970/1// 00:00:00的毫秒差
- toLocaleDateString() 年月日(字符串)
- toLocaleString() 完整的日期字符串
new Date([val])把一个时间格式字符串转化为标准时间格式
//支持格式
/*
* yy/mm/dd (hh:mm:ss)
* yy-mm-dd (hh:mm:ss) IE不支持
*
*/
DOM基本操作
- document.getElementById(),
- [context].getElementsByTagName(),
- [context].getElementsByClassName() 不兼容IE6~8
- document.getElementsByName() IE中只有表单元素的name才能识别
- document.head(获取head) / document.body(获取Body) / document.documentElement(获取HTML)
- [context].querySelector([selector]) / [context].querySelectorAll([selector]) IE6~8不兼容
节点和节点之间的关系属性
- Node(节点): 页面中所有的东西都是节点,
- 元素节点(标签):nodeType: 1, nodeName: 大写的标签名, nodeValue: null
- 文本节点: nodeType: 3, nodeName: #text, nodeValue: 文本内容
- 注释节点:nodeType: 8, nodeName: #comment, nodeValue: 注释内容
- 文档节点(document):nodeType: 9, nodeName: #document, nodeValue: null
- 非IE6~8会把空格和换行当作文本节点处理
- NodeList(节点集合): getElementsByName / querySelectorAll获取
- 描述节点的关系
- childNodes: 获取所有的子节点
- children: 获取所有的元素子节点
- parent: 获取父亲节点
- firstChild: 获取第一个子节点
- lastChild: 获取最后一个子节点
- firstElementChild / lastElementChild : 获取第一个和最后一个元素子节点(不兼容IE6~8)
- previousSibling: 获取上一个兄弟节点
- nextSiling: 获取下一个兄弟节点
- previousElementSibling / nextElementSibling: 获取上一个和下一个元素节点(不兼容IE6~8)
元素的增删改
createElement 创建元素对象 / createTextNode 创建文本对象
appendChild 把元素添加到元素末尾 / insertBefore 把元素添加到容器内指定元素前面
cloneNode(true(深)/false(浅)) 克隆元素或者节点, 深克隆把子元素也克隆,浅克隆不会
removeChild 移除容器中的某个元素
自定义属性
- 新建对象获取
- 基于setAttribute,没有放进堆内存
JS两个编程思想
- 传统操作DOM
- 操作数据,vue,react