变量声明
var声明变量带来的问题
1. 变量提升
2. 同一个作用下可以声明多次
3. 声明的变量是window对象上的属性,如果window对象下的属性和变量同名,变量将覆盖原有属性
let特性
1. 不允许重复声明
2. 不存在变量提升
3. 块级作用域 (从块的开始到声明的这段区域) 暂存死区
const特性
1. 同let特性(不能重复声明,不提升)
2. 不同于let的特性有,声明时必须赋值,赋值后不能修改
3. 但是如果声明的常量是一个对象或数组,那么对象或数组里面的数据是可以再次修改的。
变量声明总结
var声明的变量由函数划分作用域
let const声明的变量由代码块{}划分作用域
新增符号
""--模板字符串,是增强版的字符串,用反引号
表示,可以放入换行字符串(功能)
插入变量和表达式${}
<script> var a="hello"; var str=` <ul> <li>${a}</li> <li>${[1,2,3].push(4)}</li> </ul> `; console.log(str); </script>
“…”–将一个数组转换为用逗号隔开的参数序列
扩展运算符的作用
1、 用来遍历数组、对象、字符串,把他们变成逗号隔开的数据。
var arr=[…arr1]; //复制了一份
var arr=[…arr1,…arr2]; //合并两份
var o={…o1,…o2};//合并两份
2、 把逗号隔开的数据变成真正的数组。
3、 把类数组转换成真正的数组。
箭头函数
语法形式
()=>{}
()=>123 // 123为箭头函数的返回值
a=>123+a // a表示形参,只有一个参数可以不写括号,123+a作为返回值
(a,b)=>a+b // a,b两个都是形参,必须加括号
(a,b)=>( { num:a+b } ) // 返回一个对象数据,这个时候{}外面必须放一个()
箭头函数的特性
1. 函数体内的this指向的是定义函数时作用域的this 箭头函数绑定了父上下文
2. 不可以当做构造函数
3. 不可以使用arguments对象
对象简洁表示法
属性名和变量名相同,可以直接写上变量名
方法可以省略function关键字
对象的新增方法
Object.keys()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键名。 Object.values()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值。 Object.entries()
返回一个数组,成员是参数对象自身的(不含继承的)所有可遍历(enumerable)属性的键值对数组。 Object.fromEntries()
该方法是Object.entries()的逆操作,用于将一个键值对数组转为对象。 Object.assign()
合并对象:Object.assign(目标对象,源对象1,源对象2…)
数组的迭代:
ES5:
every():对数组中的每一项运行给定函数,如果该函数对每一项都返回true,则返回true。
some():对数组中的每一项运行给定函数,如果该函数对任一项返回true,则返回true。
filter():对数组中的每一项运行给定函数,返回该函数会返回true的项组成的数组。
map():对数组中的每一项运行给定函数,返回每次函数调用的结果组成的数组。
forEach():对数组中的每一项运行给定函数。这个方法没有返回值。
var numbers = [1,2,3,4,5,4,3,2,1];
var filterResult = numbers.filter(function(item, index, array){
return (item > 2);
});
alert(filterResult); //[3,4,5,4,3]
ES6:
find 找到第一个符合条件的数组元素
findIndex 找到第一个符合条件的数组元素的索引值
let arr = [1,2,3,4,5]
let arr1 = arr.findIndex((value, index, array) => value > 3)
console.log(arr1) // 3
arr.fill(target, start, end) 使用给定的值,填充一个数组
ps:填充完后会改变原数组(替换)
参数: target – 待填充的元素
start – 开始填充的位置-索引
end – 终止填充的位置-索引(不包括该位置)
let arr = [1,2,3,4,5] let arr3 = arr.fill(5,1,3) console.log(arr3)// [1, 5, 5, 4, 5]
arr.includes() 判断数中是否包含给定的值 返回true/false
与indexOf()的区别:
1 indexOf()返回的是数值,而includes()返回的是布尔值
2 indexOf() 不能判断NaN,返回为-1 ,includes()则可以判断
归并:
reduce()方法从数组的第一项开始,逐个遍历到最后。
reduceRight()则从数组的最后一项开始,向前遍历到第一项。
两个参数:一个在每一项上调用的函数和(可选的)作为归并基础的初始值。
var values = [1,2,3,4,5];
var sum = values.reduce(function(prev, cur, index, array){
return prev + cur;
});
alert(sum); //15
新增数据结构
Set数据结构
它类似于数组,但是[成员的值都是唯一的,没有重复的值]。
Set本身是一个构造函数,用来生成 Set 数据结构(键名与键值一样)
Set可以接受一个数组(或者类数组对象)作为参数,用来初始化
向Set加入值时,不会发生类型转换(类似于精确相等===),但是要注意在Set里NaN是等于自身的。另外两个对象总是不相等的
set内部的元素可以遍历【for…of…】
> var set = new Set([1, 2, 3, 4]);
> for (let i of set) {
> console.log(i);//1,2,3,4
> }
利用set数据结构给数组去重
var arr = [1,2,3,2,3, 4, 5,"1",NaN,NaN];
var s = new Set(arr);
console.log( s )// Set(7) {1, 2, 3, 4, 5, "1",NaN }
console.log( [...s] );//利用…扩展运算符把set数据结构变回数组
属性:
Set.prototype.constructor:构造函数,默认就是Set函数
Set.prototype.size:返回实例的成员总数
方法:
add():增加数据到set结构,返回新的set数据,不会增加相同的数据。
delete():删除set结构中的数据,返回true或false
has():测试set结构中是否包含某个数据,返回true或false;
clear():清除set中的所有数据,无返回值,会修改原对象;
forEach():遍历set数据结构,回调函数的参数item,index,set分别表示:数据、数据的索引(与数据一样)、set数据
s.forEach( function(item,index,set){
console.log( item,index,set )
} )
//a a Set(3) {“a”, “b”, “c”}
//b b Set(3) {“a”, “b”, “c”}
//c c Set(3) {“a”, “b”, “c”}
keys()(同理)values() 遍历set数据结构
var s = new Set(["a","b","c"]);
var key = s.keys();
console.log( key );//SetIterator {"a", "b", "c"}
console.log( key.next() );//{value: "a", done: false}
console.log( key.next() );//{value: "b", done: false}
console.log( key.next() );//{value: "c", done: false}
console.log( key.next() );//{value: undefined, done: true}
entries方法返回的遍历器,同时包括键名和键值,所以每次输出一个数组,它的两个成员完全相等
var s = new Set(["a","b","c"]);
var entries = s.entries();
console.log( entries )
console.log( entries.next() )
控制台显示结果:
/*
SetIterator {"a", "b", "c"}
{value: Array(2), done: false}
*/
Map数据结构
Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。
出现的背景:JavaScript传统上只能用字符串当作键。这给它的使用带来了很大的限制。例如:用一个对象作为键名
不同于Set的是,Set是用add方法添加,Map是用set添加,用get获取键值
delete():删除数据,返回true或false
Map的其他方法:has() forEach() keys() values() entries() 与set相同 只是多了一个键值的控制。
弱引用WeakMap/WeakSet
weakset
WeakSet结构与Set类似,也是不重复的值的集合。
WeakSet和Set的区别:
WeakSet的成员只能是对象,而不能是其他类型的值
WeakSet中的对象都是弱引用,即垃圾回收机制不考虑WeakSet对该对象的引用,也就是说,如果其他对象都不再引用该对象,那么垃圾回收机制会自动回收该对象所占用的内存,不考虑该对象还存在于WeakSet之中。这个特点意味着,无法引用WeakSet的成员,因此WeakSet是不可遍历的。
WeakMap与weakset同理
WeakMap 与 Map 在 API 上的区别主要是两个:
一是没有遍历操作(即没有keys()、values()和entries()方法),也没有size属性。
二是无法清空,即不支持clear方法。
因此,WeakMap只有四个方法可用:get()、set()、has()、delete()。
遍历接口iterator(数组、类数组、Set、Map)
检查一个对象是否部署了iterator,以数组为例。
arr[Symbol.iterator] // ƒ values() { [native code] } 说明这个对象上有iterator接口
如果该对象部署了遍历接口,就可以使用ES6提供的(keys、values、entries方法遍历)以及 for(value of obj){}遍历
Symbol
ES6 引入了一种新的原始数据类型Symbol,表示独一无二的值。它是 JavaScript 语言的第七种数据类型。
var a=Symbol();
var b=Symbol();
console.log(typeof a)//symbol
console.log(a,b);//Symbol() Symbol()
console.log(a===b);//false//可以把a,b理解为两个随机数
【使用for…in语句找不到键名为symbol数据的键值】
获得symbol数据的键值
var key=Object.getOwnPropertySymbols(obj); //找obj中symbol类型的键名
console.log(key instanceof Array);//true key是一个数组
Symbol.for(),Symbol.keyFor()
Symbol.for机制有点类似于单例模式,首先在全局中搜索有没有以该参数作为名称的Symbol值,如果有,就返回这个Symbol值,否则就新建并返回一个以该字符串为名称的Symbol值。和直接的Symbol就有点不同了。
var s1 = Symbol.for('foo');
var s2 = Symbol.for('foo');
s1 === s2 // true
Symbol.keyFor方法返回一个已登记的Symbol类型值的key。实质就是检测该Symbol是否已创建
复制代码
var s1 = Symbol.for("foo");
Symbol.keyFor(s1) // "foo"
var s2 = Symbol("foo");
Symbol.keyFor(s2) // undefined
面向对象
面向对象的特征:抽象、封装、继承、多态、重载
原型链
实例对象与原型之间的链接,叫做原型链(也叫隐式原型__proto__)
原型对象下的属性和方法
-
constructor属性
每个构造函数都有一个原型对象,该对象下有一个默认属性constructor指向该构造函数
[注意:constructor属性不能被for…in遍历的到] -
hasOwnProperty()方法
每个构造函数的原型对象下都有一个继承自Object对象下的hasOwnProperty()方法,该方法是用来测试自己身上是不是包含该属性。
如果包含则返回true,不包含则返回false。参数是字符串形式的属性。 -
toString()方法
本地对象下面都是自带的 , 自己写的对象都是通过原型链找object下面的
作用
1、把对象转成字符串
2、进制转换
3、判断对象的数据类型
检测对象的数据类型的三种方法:
arr.constructor==Array arr instanceof Array Object.prototype.toString.call(arr) == '[object Array]'
对象的继承
【什么是继承】
在原有对象的基础上,略作修改,得到一个新的对象 , 不影响原有对象的功能
【为什么要学继承】继承的作用:代码复用
【如何实现继承】 属性的继承、方法继承
拷贝继承
call修改this指向,//CreateStar.prototype = CreatePerson.prototype;//浅拷贝(改变方法内容会影响父级) for…in深拷贝
组合继承
function A(){ this.arr=[1,2,3]; }
function B(){ A.call(this) }
B.prototype=new A();
B.prototype.constructor=B;
Object.create() //浅拷贝
ECMAScript 5 通过新增Object.create()方法规范化了原型式继承。
这个方法接收两个参数:一个用作新对象原型的对象和(可选的)一个为新对象定义额外属性的对象。
let person={ name:'aa', loves:['打球','游泳'] }
let C=Object.create(person,{
name:{value:'cc'},
sayLove:{
value:function(){
console.log(this.loves)
}
}
});
es6 面向对象
类class
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log( "我叫"+this.name+"今年,"+this.age)
}
}
[在构造函数Person的原型方法中使用this,this是指向new出来的实例的] ** [for..in 取不到原型方法]
注意:构造函数的原型用Object.keys(Person.prototype)遍历,会得到一个空数组,但是理论上讲他上面应该有一个say方法
class不存在变量提升,需要先定义再使用,因为ES6不会把类的声明提升到代码头部,但是ES5就不一样,ES5存在变量提升,可以先使用,然后再定义
Object.assign方法可以给对象Person动态的增加方法,而Person.prototype = {}是覆盖对象的方法,或者在初始化的时候添加方法。
class的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
构造函数(类)身上的方法叫静态方法
class Person{
constructor(){}//不写会隐式创建
static aa(){
alert('静态方法')
}//构造函数(类)身上的方法
}
[说明:静态方法只能在静态方法中调用,不能再实例方法中调用。]
Class静态属性和实例属性 https://blog.youkuaiyun.com/qdmoment/article/details/82496685
静态属性指的是Class本身的属性,即Class.propname,而不是定义在实例对象(this)上的属性。ES6使用静态属性和实例属性:
ES6明确规定,Class内部只有静态方法,没有静态属性。
继承:
class Coder extends Person{
constructor(name,age,sex){
super(name,age);
this.sex=sex;
}
}
给对象添加属性
var person ={};
Object.defineProperty(person,'age',{value:30,writable:true,enumerable:true,configurable:true});
//writable:true--可改 enumerable:true--可被 for..in 遍历 configurable:true--可被删除
Object.defineProperties(person,{
name:(value:'lv',writable:true);
sex:(value:'man',writable:true);
})
delete person.age;//删除age属性
Object.freeze():阻止修改现有的属性
var obj = {
foo: 'bar'
}
Object.freeze(obj)