类型:JavaScript共有8种数据类型,undefined,null,Boolean,string,number,bigint,symbol,object。
其中symbol和bigint是es6中新增的。
symbol代表创建后独一无二且不可变的数据类型,主要为了解决可能出现的全局变量冲突的问题。
bigint可以安全的存储和操作大整数。
区别:
typeof 123
'number'
[] instanceof Array
true
true.constructor
ƒ Boolean() { [native code] }
Object.prototype.toString.call(123);
'[object Number]'
Array.isArray()
判断arr.__proto__ === Array.prototype
arr instanceof Array
Object.prototype.toString.call(arr);
Array.prototype.isPrototypeOf(arr);
null代表的是空对象,一般用于返回值可能为对象的变量的初始化。
undefined代表未定义,变量声明了但是未赋其值时返回值可能为undefined
原理:instanceof通过判断构造函数的prototype属性是否出现在对象的原型链中来判断数据是否属于该类型
function myInstanceOf(left, right) {
let proto = Object.getPrototypeOf(left);
let prototype = right.prototype;
while (true) {
if (!proto) {
return false;
}
if (proto === prototype) {
return true;
}
proto = Object.getPrototypeOf(proto);
}
}
console.log(myInstanceOf([], Array)); //true
console.log([] instanceof Array); //true
console.log(myInstanceOf(123, Array)); //false
console.log(123 instanceof Array); //false
因为计算机是通过二进制的方式存储数据的,所以计算机计算0.1+0.2的时候,实际上是计算的两个数的二进制的和。而这两个数的二进制都是无限循环的数。
如何相等:(n1+n2).toFixed(2);
typeof NaN; // ‘number’
NaN是一个特殊值 它和自身不相等 所以 NaN !== NaN 为true
Null和Undefined 转换成 ‘null’和’undefined’
Boolean类型 true转换’true’ false转换’false’
Number类型的值直接转换 不过极大极小的数字会使用指数形式
Symbol类型的值直接转换,但只允许显式强制类型转换
对于普通对象来说 一般会调用Object的toString()方法(Object.prototype.toString())来返回内部属性[[class]]的值,如”[object Object]“;如果对象有自己的toString()方法,字符串化时就会调用该方法并使用其返回值
Undefined类型的值转换为NaN
Null类型的值转换为0
Boolean类型的值,true转换为1 false转换为0
String类型的值转换如同使用Number()函数进行转换,如果包含非数字值则转换为NaN,空字符串为0
Symbol类型的值不能转换为数字 会报错
对象(包括数组)会首先被转换为相应的基本类型值,如果返回的是非数字的基本类型值,再遵循上述的规则将其强制转换为数字
除了 undefined null false +0 -0 NaN “” 以外 都是true
(Object.is(A,B)方法判断两个值是否是相同的值。)
双等号进行相等判断时,如果两边的类型不一致,会先进行强制类型转换后再进行比较
三等号=)进行相等判断时,如果两边的类型不一致,不会做强制类型转换,直接返回false
使用Object.is进行相等判断时,一般情况下和三等号判断相同,它处理了一些特殊情况,比如-0和+0不再相等,两个NaN是相等的
if(Json.stringify(obj) == '{}'){
console.log('空对象');
}
if(Object.keys(obj).length < 0){
console.log('空对象');
}
● let/const ● 模块化
● Class类 ● 箭头函数
● 解构赋值 ● rest参数
● Promise ● Set/Map
● 模板字符串 ● 扩展运算符
● Async/Await ● 迭代器/生成器● Symbol
导入import '模块名称' from '路径';
导出let name = 'te',age = 12; export {name,age}
模块化优点:防止命名冲突,复用性强
通过class关键字定义类,使用extends继承,子类必须在构造函数中通过super调用父类参数
箭头函数内部没有arguments
,也没有prototype
,所以不能用new
关键字调用箭头函数
箭头函数的this指向其父级对象的this
/**
* 数组的解构赋值
*/
//同时赋值多个变量
let a = 1;
let b = 2;
let c = 3;
let d = 4;
console.log(a, b, c, d); //1 2 3 4
let [e, f, g, h] = [1, 2, 3, 4];
console.log(e, f, g, h); //1 2 3 4
// 解构嵌套数组
const arr = [1, [2, 3, [4, 5, 6]]];
const [a, [b, c, [d, e, f]]] = arr;
console.log(a, b, c, d, e, f); //1 2 3 4 5 6
// 不完全解构
const [a, b, c] = [1, 2];
console.log(a, b, c); //1 2 undefined
const [d, e, [f, g]] = [3, 4, [5]];
console.log(d, e, f, g); //3 4 5 undefined
// 解构的默认值
let [a = true] = [];
console.log(a); //true
/**
* 对象的解构赋值
*/
const { foo, bar } = { foo: 'aaa', bar: 'bbb' };
console.log(foo, bar); //aaa bbb
/**
* 函数参数的解构赋值
*/
function f(options) {
let name = options.name;
let age = options.age;
let sex = options.sex;
console.log(name, age, sex); //n1 a1 s1
}
function f2({ name, age, sex }) {
// 经历了 let {name,age,sex} = options
console.log(name, age, sex); //n2 a2 s2
}
f({ name: 'n1', age: 'a1', sex: 's1' });
f2({ name: 'n2', age: 'a2', sex: 's2' });
// 解构数组类型参数
const arr = [
[1, 1],
[2, 2],
[3, 3],
[4, 4],
[5, 5],
];
arr.map(([x, y]) => {
console.log(x + y); //2 4 6 8 10
});
// 为参数设定默认值
function func({ name = 'test', age = 'test', sex = 'test' }) {
console.log(name, age, sex); //张三 test test
}
func({ name: '张三' });
/**
* 常见使用场景
*/
// 交换变量
let x = 1;
let y = 2;
[x, y] = [y, x];
console.log(x, y); // 2 1
// 取函数返回值-数组
function raf() {
return [1, 2, 3];
}
let [a, b, c] = raf();
console.log(a, b, c); //1 2 3
// 取函数返回值-对象
function rof() {
return { d: 5, e: 6 };
}
let { d, e } = rof();
console.log(d, e); //5 6
// 函数参数的定义-参数与变量名一一对应
function f1([x, y, z]) {
console.log(x, y, z); //1 2 3
}
f1([1, 2, 3]);
function f2({ x, y, z }) {
console.log(x, y, z); //2 1 3
}
f2({ z: 3, x: 2, y: 1 });
// 提取JSON数据
let jsonData = {
id: 42,
code: 200,
data: {
num: 15,
price: 32,
pname: 'tst',
},
};
let {
id,
code,
data: { num, price, pname },
} = jsonData;
console.log(id, code, num, price, pname); //42 200 15 32 tst
rest用于获取函数参数中可能存在的多余参数,rest参数必须放在最后的位置
function createV() {
console.log(arguments); //500, 200, 'test'
}
createV(500, 200, 'test');
function createB(width, height, color, ...args) {
let message = `盒子的宽度=${width},高度=${height},颜色=${color}`;
console.log(message); //盒子的宽度=200,高度=100,颜色=red
console.log(args); //[ '测试消息1', '测试消息2' ]
}
createB(200, 100, 'red', '测试消息1', '测试消息2');
详见后续
Map和Set属于ES6新增加的对象
Map 对象用于保存键值对,任何JS支持的值都可以作为key或value
与对象不同的是:
// 添加、删除成员
const m = new Map();
const o = { p: 'Hello world' };
m.set(o, 'content');
console.log('m: ', m); // Map(1) { { p: 'Hello world' } => 'content' }
console.log(m.get(o)); //content
console.log(m.has(o)); // true;
console.log(m.delete(o)); // true;
console.log(m.has(o)); // false
//接收一个数组作为参数,运行原理
const map = new Map([
['name', 'zhangsan'],
['age', '18'],
]);
console.log('map:', map); //map: Map(2) { 'name' => 'zhangsan', 'age' => '18' }
console.log(map.has('name')); //true
let arr = [
['name', 'zhangsan'],
['age', '18'],
];
const map1 = new Map();
arr.forEach(([key, value]) => map1.set(key, value));
console.log('map1: ', map1); //map1: Map(2) { 'name' => 'zhangsan', 'age' => '18' }
// map的键和内存地址绑定, k1 k2 值相同但是内存地址不同
let k1 = ['a'];
let k2 = ['a'];
const map3 = new Map();
map3.set(k1, 111).set(k2, 222);
console.log(map3.get(k1)); // 111
console.log(map3.get(k2)); // 222
Map实例的属性
Map.prototype.size()
:返回Map结构的成员总数
Map实例的方法分为两大类,操作方法和遍历方法
操作方法:
Map.prototype.set(key, value)
:set方法设置键名key对应的键值为value,然后返回整个 Map 结构。如果key已经有值,则键值会被更新,否则就新生成该键。
Map.prototype.get(key)
:get方法读取key对应的键值,如果找不到key,返回undefined。
Map.prototype.has(key)
:has方法返回一个布尔值,表示某个键是否在当前 Map 对象之中。
Map.prototype.delete(key)
:delete方法删除某个键,返回true。如果删除失败,返回false。
Map.prototype.clear()
:clear方法清除所有成员,没有返回值。
遍历方法:
Map.prototype.keys()
:返回键名的遍历器。
Map.prototype.values()
:返回键值的遍历器。
Map.prototype.entries()
:返回所有成员的遍历器。
Map.prototype.forEach()
:遍历 Map 的所有成员。
Map的遍历顺序就是插入顺序
// 操作方法
const map = new Map();
map.set('foo', true);
map.set('bar', false);
console.log(map.size); //2
const m = new Map();
m.set('edition', 6); //键是字符串
m.set(262, 'standard'); //键是数字
m.set(undefined, 'nah'); //键是undefined
// 链式写法
let map2 = new Map().set(1, 'a').set(2, 'b').set(3, 'c');
const m2 = new Map();
const hello = () => {
console.log('hello');
};
m2.set(hello, '123'); //键是函数
console.log(m2.get(hello)); //123
const m3 = new Map();
m3.set('edition', 6);
m3.set(262, 'standard');
m3.set(undefined, 'nah');
console.log(m3.has('edition')); //true
console.log(m3.has(262)); //true
console.log(m3.has(undefined)); //true
console.log(m3.has('123')); //false
m3.delete(262);
console.log(m3.has(262)); //false
console.log(m3.size); //2
m3.clear();
console.log(m3.size); //0
// 遍历方法
const map4 = new Map([
['F', 'no'],
['T', 'yes'],
]);
console.log('map4: ', map4);
for (let key of map4.keys()) {
console.log(key); // F T
}
for (let value of map4.values()) {
console.log(value); // no yes
}
for (let item of map4.entries()) {
console.log(item[0], item[1]); // F no, T yes
}
// 或者
for (let [key, value] of map4.entries()) {
console.log(key, value); // F no, T yes
}
// map转数组
const map5 = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
console.log([...map5.keys()]); //[ 1, 2, 3 ]
console.log([...map5.values()]); //['one', 'two', 'three']
console.log([...map5.entries()]); //[ [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ] ]
console.log([...map5]); //[ [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ] ]
const map6 = new Map().set(1, 'a').set(2, 'b').set(3, 'c');
let newMap1 = new Map(
[...map6].filter(([key, value]) => {
return key < 3 && value != 'b';
})
);
console.log('newMap1: ', newMap1); //newMap1: Map(1) { 1 => 'a' }
let newMap = new Map(
[...map6].map(([key, value]) => {
return [key * 2, '_' + value];
})
);
console.log('newMap: ', newMap); //newMap: Map(3) { 2 => '_a', 4 => '_b', 6 => '_c' }
map6.forEach((value, key, mapS) => {
console.log('Key: %s, Value: %s', key, value);
// Key: 1, Value: a
// Key: 2, Value: b
// Key: 3, Value: c
});
// map转换为数组
const map5 = new Map([
[1, 'one'],
[2, 'two'],
[3, 'three'],
]);
console.log('[...map5]: ', [...map5]); //[...map5]: [ [ 1, 'one' ], [ 2, 'two' ], [ 3, 'three' ] ]
let newArr = [];
for (let [key, value] of map5.entries()) {
newArr.push(key);
newArr.push(value);
}
console.log('newArr: ', newArr); //[ 1, 'one', 2, 'two', 3, 'three' ]
// 数组转为Map
const map6 = new Map([
[1, 2],
[3, 4],
]);
console.log('map6: ', map6); //map6: Map(2) { 1 => 2, 3 => 4 }
// Map转为对象 如果所有 Map 的键都是字符串,它可以无损地转为对象。
function strMapToObj(strMap) {
let obj = Object.create(null);
for (let [key, value] of strMap) {
obj[key] = value;
}
return obj;
}
const myMap = new Map().set('yes', true).set('no', false);
strMapToObj(myMap);
console.log('myMap: ', myMap); //myMap: Map(2) { 'yes' => true, 'no' => false }
Set 类似于数组,但其成员值都是唯一的,没有重复的值,Set内部值判断类似于===所以5和’5’是两个不同值,在Set内部 NaN等于自身,所以Set实例内只会存在一个NaN。
// 数组去重
const s = new Set();
[2,3,4,5,5,2,2,].forEach(x => s.add(x))
console.log(s)
for(let i of s){
console.log(i);//2 3 4 5
}
let arr = [1,2,2,3,4,5,5,4,4,2,1]
let t = new Set(arr);
console.log('t: ', t);//t: Set(5) {1, 2, 3, 4, 5}
// 字符串去重
let str = 'aaabbcscdsa';
let s1 = [...new Set(str)].join('');
console.log('s1: ', s1);//s1: abcsd
// NaN
let set3 = new Set();
let a = NaN;
let b = NaN;
set3.add(a);
set3.add(b);
console.log(set3);//Set(1) {NaN}
Set实例的属性
Set.prototype.constructor
:构造函数,默认就是Set函数
Set.prototype.size
:返回Set实例的成员总数
Set的实例方法分为两大类,操作方法和遍历方法
操作方法:
Set.prototype.add()
:添加某个值,返回Set结构本身。
Set.prototype.delete(value)
:删除某个值,返回一个布尔值,表示删除是否成功。(会改变原有结构)
Set.prototype.has(value)
:返回一个布尔值,代表该值是否为Set的成员。
Set.prototype.clear()
:清除所有成员,没有返回值。
遍历方法:
Set.prototype.keys()
:返回键名的遍历器
Set.prototype.values()
:返回键值的遍历器
Set.prototype.entries()
:返回键值对的遍历器
Set.prototype.forEach()
:使用回调函数遍历每个成员
因为set是类似数组的结构,所以keys和values返回值其实一样。
let set = new Set(['red', 'red', 'green', 'yellow']);
for (let value of set.keys()) {
console.log(value); // red green yellow
}
for (let value of set.values()) {
console.log(value); // red green yellow
}
for (let en of set.entries()) {
console.log(en); // [ 'red', 'red' ]['green', 'green'][('yellow', 'yellow')];
}
set.forEach((ele) => console.log(ele)); // red green yellow
// 遍历的应用
let set1 = new Set(['red', 'green', 'yellow']);
let arr = [...set1];
console.log(arr); //[ 'red', 'green', 'yellow' ]
// 去重
let arr2 = [1, 3, 4, 5, 2, 31, 31, 31, 1, 2, 3];
let unique = new Set(arr2);
console.log(unique); //Set(6) { 1, 3, 4, 5, 2, 31 }
this is ${value}
rest用于函数形参 扩展运算符用于实参
const str = ['a', 'b', 'c'];
function printS() {
console.log(arguments);
}
printS(str); //参数为一个数组,其中包含三个元素
printS(...str); //参数为三个元素
// 数组合并
const s1 = ['a', 'b', 'c'];
const s2 = ['d', 'e'];
let es5 = s1.concat(s2);
console.log('es5: ', es5); //es5: [ 'a', 'b', 'c', 'd', 'e' ]
let es6 = [...s1, ...s2];
console.log('es6: ', es6); //es6: ['a', 'b', 'c', 'd', 'e']
// 数组的克隆
const s3 = [...s2];
console.log('s3: ', s3); //s3: [ 'd', 'e' ]
// 将伪数组转化为真正的数组
function argToArray() {
let arr = [...arguments];
return arr;
}
let s4 = argToArray(1, 2, 3, 4);
console.log('s4: ', s4); //s4: [ 1, 2, 3, 4 ]
详见Async/Await
未完待续
未完待续
let是块级作用域,var变量在函数外声明是全局作用域,let在变量未声明之前使用会直接报错,var不会;let禁止重复声明,var可以重复声明;变量在函数内部是局部作用域,变量仅在函数内生效。
const 一.const为常量声明方式,声明变量时必须初始化,后面出现的代码不能再修改该常量的值。 二.const实际上保证的并不是变量的值不得改动,而是指向变量的那个内存地址不得改动,所以定义的对象属性值可以改变。
箭头函数是es6中提出来的,它没有prototype,也没有自己的this指向,更不可以使用arguments参数,所以不能new一个箭头函数
new操作符的实现步骤如下:
1.创建一个对象
2.将构造函数的作用域赋值给新对象
(也就是将对象的__proto__属性指向构造函数的prototype属性)
3.指向构造函数中的代码,构造函数的this指向该对象
(也就是为这个对象添加属性和方法)
4.返回新对象
function student(name,age){
this.name = name;
this.age = age;
}
function createStu(constructor,...args){
let obj = Object.create(null);
Object.setPrototypeOf(obj,constructor.prototype);
let result = constructor.apply(obj,args);
return result instanceof Object ? result : obj;
}
for in 用于遍历对象时,得到的值为对象的key;遍历字符串或者数组时,得到的值为下标。
for of 不能遍历对象;遍历数组或者字符串时,得到的每一个值
for of 用于获取键值对的——值
for in 用于获取键值对的——键 value of key in 获取值用of 获取下标、键用in
const obj = {
a: 1,
b: 2,
c: 3,
};
for (let item in obj) {
console.log(item); // a b c
}
// for (let value of obj) {
// console.log(value);//报错
// }
const arr = [4, 5, 6];
for (let item in arr) {
console.log(item); //0 1 2
}
for (let item of arr) {
console.log(item); //4 5 6
}
const str = 'test';
for (let item in str) {
console.log(item); //0 1 2 3
}
for (let item of str) {
console.log(item); //t e s t
}
(1)首先创建了一个新的空对象
(2)设置原型,将对象的原型(protp)设置为函数的prototype对象
(3)让函数的this指向这个对象,执行构造函数的代码(为这个新对象添加属性)
(4)判断函数的返回值类型,如果是值类型,返回创建的对象;如果是引用类型,就返回这个引用类型的对象。
function student(name, age) {
this.name = name;
this.age = age;
}
function createStu(constructor, ...args) {
// 创建空对象
let obj = Object.create(null);
// 将空对象的__proto__ 指向构造函数的prototype
Object.setPrototypeOf(obj, costructor.prototype);
// 将obj绑定到构造函数上,便可以访问构造函数中的属性
let result = constructor.apply(obj, args);//obj.constructor(args);
// 如果result是一个对象则返回 否则返回obj
return result instanceof Object ? result : obj;
}
let stu1 = createStu(student, 'rte', '12');
console.log('stu1: ', stu1); //stu1: student { name: 'rte', age: '12' }
数组转字符串:toString() join() join可以指定转换为字符串时的分隔符
操作数组 尾部 pop() push() 头部 shift() unshit()
数组连接 concat() 返回的是拼接好的数组 不影响原数组
数组截取 slice() 截取数组一部分返回 不影响原数组
数组插入 splice() 影响原数组
查找特定项索引的方法 indexOf() lastIndexOf()
遍历的 map() forEach() filter()
DOM是指文档对象模型,它指的是把文档当作一个对象,这个对象主要定义了处理网页内容的方法和接口,DOM的最根本对象的document。
BOM是指浏览器对象模型,它指的是把浏览器当作一个对象来看,这个对象主要定义了与浏览器交互的方法和接口,BOM的核心是window。
window 对象含有 location 对象、navigator 对象、screen 对象等子对象,并且 DOM 的最根本的对象 document 对象也是 BOM 的 window 对象的子对象。
arguments是一个对象,它的属性是从0开始依次递增的数字,还有callee和length等属性,与数组相似,但是它却没有数组常见的方法属性,比如forEach,所以它们叫类数组
遍历类数组有三种方法
//一 使用call 将数组的方法应用到类数组上,
function foo() {
Array.prototype.forEach.call(arguments, (a) => console.log(a));
}
foo(1, 23, 4, 45, 6); // 1 23 4 45 6
// 二 使用 Aarry.form()将类数组转换为数组
function foo() {
const arrArgs = Array.from(arguments);
arrArgs.forEach((a) => console.log(a));
}
foo(1, 23, 4, 45, 6); // 1 23 4 45 6
// 三 使用展开运算符将类数组转化为数组
function foo() {
const arrArgs = [...arguments];
arrArgs.forEach((a) => {
console.log('a: ', a);
});
}
foo(1, 23, 4, 45, 6); // 1 23 4 45 6
// 通过call调用数组的slice方法
Array.prototype.slice.call(arrayLike); //效果相当于arrayLike.slice();
// 通过call调用数组的splice方法
Array.prototype.splice.call(arrayLike,0);
// 通过apply调用数组的concat方法
Array.prototype.concat.apply([],arrayLike);
Array.from(arrayLike);