API
: 所有可以供别人调用
的方法
/接口
,统称为API
API
全称是application programming interface
,应用程序接口;
要学习英语单词
,因为一般中文文档
会加一些作者的想法
,但那想法
并不一定正确
。
ide
就是开发工具
程序员三种病
数组方法
[].push()
[].pop()
[].unshift()
[].shift()
[].splice()
[].indexOf()
[].lastIndexOf()
[].includes()
[].toString()
[].join()
[].slice()
[].concat()
[].sort()
[].reverse()
[].forEach()
[].map()
键值对
组成的属性名和属性值集合
键值对
就是对象
的一个成员
obj.name
obj对象
中的name这个成员
对象的成员访问
"string".charAt()
"string".charCodeAt()
"string".slice()
"string".substring()
"string".substr()
"string".indexOf()
"string".lastIndexOf()
"string".includes()
"string".toUpperCase()
"string".toLowerCase()
"string".replace()
"string".split()
Math.abs()
Math.ceil()
Math.floor()
Math.round()
Math.random()
Math.max()
Math.min()
Math.sqrt()
Math.pow()
//2^10 -> 1024
Math.pow(2,10)//2的10次方
2**10//2的10次方
new Date()
创建当前时间的日期对象
new Date().getFullYear()
new Date().getMonth()
new Date().getDay()
new Date().getDate()
new Date().getHours()
new Date().getMinutes()
new Date().getSeconds()
new Date().getMilliseconds()
new Date().getTime()
获取DOM元素
节点关系属性
增删改[自定义属性]
循环:for 、for in 、while、do-while
判断:if-else、switch-case、三元运算符
ECMAScript是JS的语法规范
ES3[很老的规范]
ES5[在ES3的基础上,新增了很多便于开发的API方法,例如:forEach/map] =>不兼容IE6~8
以ES5为分隔,ES5是JS的老版本语法规范!ES6是js的新语法规范。
ES6新语法规范[ES6+: ES6~ES12]
以后习惯用===用来比较。
ES6+新增的数据结构
Symbol(描述)
都会创建
一个唯一值
console.log(Symbol() === Symbol()); //false
console.log(Symbol('AA') === Symbol('AA')); //false
一个对象中,其成员值(属性值/value)可以是任意类型!
在ES6之前,其成员(属性名/key),都是“字符串”类型!「不论是设置还是访问成员,只要成员的类型不是字符串,都先转换为字符串,再进行处理」
let arr = [10, 20];
let sym = Symbol('BB');
let obj = {
0: 100, //成员:'0'
1: 200, //成员:'1'
length: 2, //成员:'length'
true: '哈哈哈', //成员:'true'
null: '呵呵呵', //成员:'null'
fn: function () { }, //成员:'fn'
// 此处设置中括号,仅仅是语法要求:把变量的值作为成员
[arr]: '嘿嘿嘿',
[Symbol('AA')]: 1000,
[sym]: 2000
};
obj[arr] = '嘿嘿嘿'; // obj[String([10, 20])] -> obj['10,20']
console.log(obj); // { '10,20':'嘿嘿嘿',.... }
console.log(obj[0], obj['0']); //100 100
// obj[0] -> obj['0'] 默认先把0变为字符串"0",再去对象中进行成员访问
let length = 1;
console.log(obj['length']); //2
console.log(obj[length]); //先获取length变量的值,再拿这个值作为对象的成员去访问 obj[length]->obj['1']
console.log(obj.length); //2「同方式一」
在ES6及以后,对象中的成员不单纯是字符串类型,还可以是symbol类型了!
设置的唯一值成员,如果后期想访问:先用变量存储创建的唯一值,然后设置和获取的时候,都基于这个变量进行操作!先用变量存储创建的唯一值,然后设置和获取的时候,都基于这个变量进行操作!
let arr = [10, 20];
let sym = Symbol('BB');
let obj = {
0: 100, //成员:'0'
1: 200, //成员:'1'
length: 2, //成员:'length'
true: '哈哈哈', //成员:'true'
null: '呵呵呵', //成员:'null'
fn: function () { }, //成员:'fn'
// 此处设置中括号,仅仅是语法要求:把变量的值作为成员
[arr]: '嘿嘿嘿',
[Symbol('AA')]: 1000,
[sym]: 2000
};
console.log(obj["Symbol('AA')"]); //undefined 此成员就是symbol类型,并没有给其转换为字符串
console.log(obj[Symbol('AA')]); //undefined 按照symbol类型的成员获取值,获取不到的原因是:两次是不同的唯一值
console.log(obj[sym]); //2000
可以基于一些API方法,获取对象中的所有成员(属性名):返回包含成员的数组集合
let arr = [10, 20];
let sym = Symbol('BB');
let obj = {
0: 100, //成员:'0'
1: 200, //成员:'1'
length: 2, //成员:'length'
true: '哈哈哈', //成员:'true'
null: '呵呵呵', //成员:'null'
fn: function () { }, //成员:'fn'
// 此处设置中括号,仅仅是语法要求:把变量的值作为成员
[arr]: '嘿嘿嘿',
[Symbol('AA')]: 1000,
[sym]: 2000
};
console.log(Object.keys(obj)); //获取对象的私有属性,但是只能获取 可枚举、字符串类型(非symbol类型) 的私有属性 -> ['0', '1', 'length', 'true', 'null', 'fn', '10,20']
console.log(Object.getOwnPropertyNames(obj)); // 获取对象的私有属性,但是只能获取 字符串类型(非symbol类型) 的私有属性「好处:不考虑枚举性」 -> ['0', '1', 'length', 'true', 'null', 'fn', '10,20']
console.log(Object.getOwnPropertySymbols(obj)); // -> [Symbol(AA), Symbol(BB)] 获取当前对象中,所有 symbol 类型的私有属性!!「好处:不考虑枚举性」
// 获取对象所有的私有属性「不论类型、不论是否可以枚举」
// let keys = Object.getOwnPropertyNames(obj);
// keys = keys.concat(Object.getOwnPropertySymbols(obj));
let keys = Reflect.ownKeys(obj); //这一个操作,代替了上面两个操作「ES6新提供的方法」
keys.forEach(key => {
console.log(key); //迭代的每个成员
console.log(obj[key]); //迭代的每个成员值
});
typeof 值
let obj={x:10};
typeof 值
返回这个值的数据类型
检测除null以外的原始值类型「性能高」
笼统的校验是否为对象
// 笼统的检测一个值是否为对象
const isObject = function isObject(value) {
let type = typeof value; //这个值的检测结果
// 是对象的条件:不能是null,并且基于typeof检测的值是 'object'/'function' 中的一个
return value !== null && (type === 'object' || type === 'function');
};
console.log(isObject(10)); //false
console.log(isObject(null)); //false
console.log(isObject([])); //true
console.log(isObject({})); //true
console.log(isObject(function () { })); //true
检测是否为函数 => if(typeof obj===“function”){…}
处理浏览器兼容「ES6+语法规范,都不兼容IE」
if (typeof Symbol !== 'undefined') {
// 当前浏览器支持Symbol
// ...
}
计算机的内存:
在计算机的编程语言中,我们声明的变量
& 数据类型值
,都存储在计算机的 虚拟内存
中
1B 1个字节[一个字母/数字,是一个字节、一个汉字是两个字节]
1KB 1024B=1KB
1MB 1024KB=1MB
1GB 1024MB=1GB
1TB 1024GB=1TB
整数部分
除以2,取余数,用本次“商值”继续除以2…直到商数为0结束
把所有取的余数“倒过来”拼接
let num = 18;
console.log(num.toString(2)); //toString中支持传递进制,把数字转换为指定进制的字符串 '10010'
/*
18 / 2 = 9 余 0
9 / 2 = 4 余 1
4 / 2 = 2 余 0
2 / 2 = 1 余 0
1 / 2 = 1 余 1
.....
*/
小数部分
乘以2,取整数部分,然后继续乘以2…
直到乘积是1,这样取完整只剩0,则停止相乘
let num = 0.3;
console.log(num.toString(2)); //'01001100110011001....'
/*
0.3 * 2 = 0.6 0
0.6 * 2 = 1.2 1
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
0.6 * 2 = 1.2 1
0.2 * 2 = 0.4 0
0.4 * 2 = 0.8 0
0.8 * 2 = 1.6 1
.....
*/
问题:一定会有无限循环的
为什么0.1+0.2!==0.3
?
console.log((0.1 + 0.2) === 0.3); //false
原因: 0.1 + 0.2=0.30000000000000004
?「以小组为单位探索这个问题」
const the01All = (0.1).toString(2)
const the02All = (0.2).toString(2)
const the03All = (0.3).toString(2)
const the034All = (0.30000000000000004).toString(2)
console.log(the01All.slice(0,51),'0.1')
console.log(the02All.slice(0,51),'0.2')
console.log(the03All.slice(0,51),'0.3')//0.1与0.2的二进制相加得到0.3的二进制表示。但JavaScript中浮点数是有位数的,最多50位有效数字。故而0.3的二进制表示得到的是与0.30000000000000004相同的表示,而0.30000000000000004二进制表示方式中,反转成十进制时,得到的是0.30000000000000004。
console.log(the034All.toString(2).slice(0,51),'0.30000000000000004')
console.log(the034All.toString(2).slice(0,51)===the03All.slice(0,51),'比较')
怎么解决精准度丢失的问题?
题目
let arr = [27.2, 0, '0013', '14px', 123];
arr = arr.map(parseInt);
console.log(arr);
map()语法
/*
map的语法:
+ 数组中有多少项,就迭代多少次,对应的:传递进来的回调函数,就要被执行多少次
+ 每一次函数执行,都会把当前迭代这一项的值和索引传递给函数
+ 回调函数返回啥,就是把数组当前迭代这一项替换为啥「原始数组不变,以新数组返回」
*/
let arr = [10, 20, 30];
arr = arr.map((item, index) => {
// 执行三次
// @1 item=10 index=0 return 0;
// @2 item=20 index=1 return 20;
// @3 item=30 index=2 return 60;
return item * index;
});
console.log(arr); //[0,20,60]
parseInt()语法及进制转换
/*
parseInt([value]):必须要确保[value]是个字符串,如果不是,则先把其转换为字符串;然后从字符串左侧开始查找,找到有效的数字字符(10进制的),直到遇到一个非有效数字字符结束(不论后面是否还有)则停止查找;把找到数字字符转换为数字(10进制的),如果一个都没找到,则结果是NaN!
*/
console.log(parseInt('10px')); //'10' -> 10
console.log(parseInt('10.2px')); //'10' -> 10
console.log(parseInt('px10')); //'' -> NaN
console.log(parseInt(null)); //'null' -> NaN
console.log(parseInt('')); //->NaN
console.log(parseInt(true)); //->'true' -> NaN
/*
parseInt([value],[radix]):
+ 如果没有写[radix],或者写的0,则默认是10进制「有特殊情况:如果字符串是以0x开始,则默认值是16」
+ 如果[radix]的范围不在2~36之间,则直接返回NaN
+ 从左侧[value]字符串中,找出所有符合[radix]进制的字符,最后把这些字符,看做[radix]进制,转为10进制!
*/
console.log(parseInt('14635px'));
/*
parseInt('14635px',10)
找到所有符合10进制的字符 '14635'
最后转为10进制 14635
*/
console.log(parseInt('14635px', 5));
/*
找到所有符合5进制的字符 '14'
把其看做5进制,转10进制的数字「知识点:把N进制转10进制 -> 按权展开求和」
把N进制转10进制(个位数权重是0,十位数是1,百位数是2...)
--> ... + 百位数*N^2 + 十位数*N^1 + 个位数*N^0
1*5^1 + 4*5^0 = 5 + 4 = 9
*/
/*
parseInt也是一个函数;数组有五项,所以迭代五次;每一次迭代,都把parseInt函数执行,并且把当前迭代这一项及其索引传递给parseInt;最后只要分析出parseInt每一次执行的结果,我们就知道最终数组每一项都是啥了!
第一次迭代 parseInt(27.2,0) => 27
parseInt('27.2',10)
找到符合10进制的字符 '27'
把其转换为10进制的数字 27
第二次迭代 parseInt(0,1) => NaN
没有1进制
第三次迭代 parseInt('0013',2) => 1
找到符合2进制的字符 '001'
把其转换为10进制的数字
0*2^2 + 0*2^1 + 1*2^0 = 0+0+1
第四次迭代 parseInt('14px',3) => 1
找到符合3进制的字符 '1'
把其转换为10进制的数字
1*3^0
第五次迭代 parseInt(123,4) => 27
parseInt('123',4)
找到符合4进制的字符 '123'
把其转换为10进制的数字
1*4^2+2*4^1+3*4^0 = 16+8+3 => 27
*/
let arr = [27.2, 0, '0013', '14px', 123];
arr = arr.map(parseInt);
console.log(arr);//[ 27, NaN, 1, 1, 27 ]
变种:
let arr = [27.2, 0, 0013, '14px', 123];
arr = arr.map(parseInt);
console.log(arr);
/*
只看第三项 parseInt(0013,2)
浏览器看到 0013 后,首先会默认把其转换为10进制(8->10)
0*8^3+0*8^2+1*8^1+3*8^0 = 0+0+8+3 = 11
parseInt(11,2)
parseInt('11',2)
找符合2进制的字符 '11'
把其转换为10进制的值
1*2^1+1*2^0 = 2+1 = 3
这一块有一个特殊的知识点:在JS中,以“0”开始的“数字”,浏览器会默认把其作为8进制转10进制
*/