一.基础
es5发布于2009年 其实用的是99年发布的ecma3.0改进的3, es6发布于15年
babel进行es6的转译编码但是不能转译api 可以通过babel-polyfill进行转译
二.let/const
let变量不提升 不能重复 且同一作用域下不能声明同样名称的两次 包括函数
可以用let 来解决闭包的问题,因为每循环一次就产生一次作用域
var arr = [];
for(let i = 0; i< 10 i++){
arr[i] = function(){
console.log(i)
}
}
for(var k = 0; k <10; k++){
arr[k]();
}
//输出0-9
//可以拿到i得值
for(let i = 0; i<10; i++){
i = 'a';
console.log(i);
}
输出a
//这样又报错
for(let i = 0; i<10; i++){
var i = 'a';
console.log(i);
}
这到底是为什么呢?到底是不是在同一个作用域下呢?一会变量提升 一会却又触发了第一个条件
//输出了10个10 所以证明了一点 如果用Let是不在一个作用域得,这就叫做父子级嵌套
for(let i = 0; i<10;i++){
let i = 'a';
console.log(i);
}
//因为var 会提升所以导致和父级的冲突,而let不会提升,则就是独立的作用域有一点
//点立即执行函数的意思
const 不能更改值 有tdz 不能在同一作用域下声明两次,但是会发生如果const 的值是对象的话是可以更改的,这是堆栈问题造成的,所以要通过OBject.freeze来循环冻结这个属性
const obj = [];
Object.freeze(obj);
obj[2] = 'zhangsan';//无效
//循环冻结
function myFreeze(obj){
Object.freeze(obj);
for(var key in obj){
if(typeof(obj[key]==='object')&& obj[key]!==null){
Object.freeze(obj[key]);
}
}
}
三.函数默认值及结构赋值
(1).虚值
function foo(x,y){
x = x || 1;
y = y || 2;
console.log(x+y);
}
foo(); //3
foo(5,6); //11
foo(5); //7
foo(null,6);//7
foo(0,5);//6 这里就会出问题这是falsy(虚值Boolean为假的值),我赋值的是0
//es5解决方案
function foo(x,y){
var a = typeof(argument[0]!=='undefined' ? arguments[0]:1);
var b = typeof(argument[1]!=='undefined' ? arguments[1]:2);
console.log(a+b);
}
foo(); //3
foo(5,6); //11
foo(5); //7
foo(null,6);//7
foo(0,5);//5
//es6
function foo(x=1,y=2){
console.log(x+y);
}
//调用与上方结果一致
(2).作用域总结
let x = 1;
function foo(y=x){
let x = 2
console.log(y);
}
foo()//输出1
function foo(x=2){
let x = 2
console.log(x)
}
foo()//这样又会报错
(3).数组结构
let[a,b = 2] = [1,null]
console.log(a,b)//1 null 如果是un则就是默认值,其余的都是传入的值
function test(){}
let [x = test()] = []
console.log(x);//un 因为函数默认返回值是undefined
(4).对象的结构
let {a=2,b,c,d,e,f,g,h} = {b:2,c:3,e:4,f:5}
console.log(a,b,c,d,e,f,g) //2 2 3 un un 4 5 un un
(5).结构深入
let a1 = [1, 2, 3], obj = {};
[obj2.a,obj2.b,obj.c] = a1;
console.log(obj2.a, obj.b, obj2.c);//1 2 3
let a = 10, b = 20;
[b,a] = [a,b]
let {a: x,a: x} = {a: 1};
console.log(x,x)//会报错,不要重复定义
let {a: x,a: y} = {a: 1};
console.log(x,y);//这样也是可以的
数组
function test([x, y]){
console.log(x);
console.log(y);
}
test([1, 2]);//打印1,2
对象
function foo({x, y}){
console.log(x,y)
}
foo({x: 1, y:2})//打印1,2
//字符串转数组
const [a, b, c, d, e] = 'hello';
console.log(a, b, c, d, e); //输出h e l l o
//调用属性
let {length: len} = 'hello';
console.log(len);//输出5
let {toString: s} = 123;
console.log(s);//输出f tostring(){[native code]}
console.log(s === Number.prototype.toString)//true
let {toString: s} = true;
console.log(s === Boolean.prototype.toString)//true
布尔值,number,string都能进行隐式转换
let {prop} = null;
log(prop);
首先会造成length不在准确只能获取到es6之前的参数长度
function test(a, b, c = 1){}
test(1);
console.log(test.length);//输出2
function test(c = 1, a, b){}
test(1);
console.log(test.length);//输出0
function test(a,b,c = 1, d, e, f){}
test(1);
console.log(test.length);//依然是2
说明es6的默认值会造成length实效
function test(a, b, d, e, f, f = 1){
arguments[1] = 7;
console.log(arguments);
}
test(1, 2, 3, 4, 5, 6);
console.log(test.length);
//一旦给了默认值就会造成映射失效。输出1723456,
//虽然arguments改变了,但是由于没有了映射关系导致形参值是没有改变的
function fetch(url,{body = "",method = "get"} = {})
fetch('http://www');
四.箭头函数/拓展运算符
(1).箭头函数
const full = ({first,last} = {} ) => first +''+last;
console.log(full({first:3,last:5}))//输出3,5//输出3,5
var arr = [123,12,31,23,1,4,4213,3213,43];
var arr1 = arr.sort((a,b) => a - b)
即可排序
1.this.为外层的函数作用域来决定(箭头函数的作用域是父级的作用域,而不是父级)
function foo(){
log(this)
return (a) =>{
log(this.a)
}
}
var obj1 = {a:2};
var obj2 = {a:3};
var bar = foo.call(obj1);
bar.call(obj2)//输出还是2
const person = {
eat(){
log(this);
},
drink:()=>{
log(this);
}
}
person.eat();{eat:f,drink:f}
person.drink();Window{...}
function foo(){
return () =>{
return ()=>{
return ()=>{
console.log('id',this.id)
}
}
}
}
var f = foo.call({id: 1});
var f1 = f.call({id:2})()(); id1
var f2 = f().call({id:3})(); id1
var f3 = f()().call({id:4}); id1
寻找thisl流程:那么父级=无效-无效-无效={id:1}
function foo(){
setTimeout(()=>{
log(arguments);//1234567
})
}
foo(1,2,3,4,5,6,7)//这里拿的是父级的arg
总结:箭头函数应用于没有递归,执行语句较少,不需要需要引用函数名,不需要实例化的时候
(2).rest
收集多数用在形参上,可以将传入的值变为数组,但是收集必需是最后一个参数
//将值收集为数组
var sum = (...args) =>{
log(args[0]+args[1])
}
sum(1,2)
//收集必需是最后一个参数
let fn =(a,b,c,...d) =>{}
//将数字展开为各个值
function foo(x, y, z){
console.log(x, y, z)
}
foo(...[1,2,3])
foo(...[1,2,3,3,4,5])//不影响
五.es6乱七八糟的函数
(1).描述符
Object.getOwnPropertyDescriptor(obj,'a')
let obj = {a: 2};
log(Object.getOwnPropertyDescriptor(obj,'a'));
{
configurable: true,
enumerable: true,
value: 2,
writable: true
}
Object.defineProperty(obj,'a',{})
let obj = {};
Object.defineProperty(obj,'a',{
value: 2,
enumberable:true,
writable:true
configurable: true
})
log(obj);//输出{a: 2}
把configturable变为false则无法继续配置第二次
这时就牵扯了静默失败,而且严格模式下还会报错,就是当把writable改变为false时去改值就会静默失败
(2).getter/setter
var obj = {
log:['example','test'],
get latest(){
if(this.log.length === 0)return undefined;
return this.log[this.log.length-1]
}
}
log(obj.latest)//test
var myObject = {
get a(){
return 2;
}
}
Object.defineProperty(myObject,'b',{
get: function(){
return this.a*2
},
enumerable: true
})
log(myObject.a) 2
log(myObject.b) 4
在get函数情况下value 和 writable是不能设置的,而configuable和enumerable是可以用的
var myObject ={
get a(){
return 2;
}
}
Object.defineProperty(myObject,'b',{
get: function(){
return this.a *2;
},
enumerable:true,
value: 6
})//会报错
var obj = {
get a(){
return this._a;
},
set a(val){
return this._a = val *2
}
}
obj.a = 3;
log(obj.a);//6
总结:getter setter操作,覆盖了原本的 [[get]],[[put]]
(3).对象密封的4种方式
const obj = {
get foo(){
},
set foo(x){
}
}
log(obj.foo.name)//这样会报错因为打印Obj.foo == un
var descriptor = Object.getOwnPropertyDescriptor(obj,'foo');
log(descriptor.get.name);//打印get foo set访问也同理
密封方式一preventExtensions/isExtensible
阻止拓展
var obj = {a: 2};
log(Object.preventExtensions(obj));//{a: 2};
obj.b = 3;
log(obj);//{a:2}
查看是否可以拓展
log(Object.isExtensible(obj)); //false 不可拓展
特性
严格模式下会报错
会报错 不会静默失败
var obj = {a: 2};
Object.preventExtensions(obj);
Object.defineProperty(obj,'b',{
value: 6
})
var obj = {a : 2};
Object.seal(obj);
console.log(Object.isSealed(obj))//true
没有被密封 底层把所有的configurable改为false
Object.freeze(obj);
log(Object.isFrozen(obj));
function myFreeze(obj){
Object.freeze(obj);
for(var key in obj){
if(typeof(obj[key]) === 'object' && obj[key] !== null){
myFreeze(obj[key])
}
}
}
总结:
(4).is
log(+0 === -0);//true
log(NaN === NaN);//false
log(Object.is(NaN,NaN))//true
log(Object.is(+0,-0))//false
(5).assign对象合并
let obj = {a: 1};
let tar = {};
let copy = Object.assign(tar,obj);
log(copy);//{a: 1}
log(copy === tar) //true
log(copy === obj) //false
证明assign返回的对象就是原对象
合并
const tar = {a: 1};
const tar2 = {b: 2};
const tar3 = {c: 3};
Object.assign(tar,tar2,tar3)
log(tar);//{a:1,b:2,c:3}
覆盖
const tar = {a:1,b:1};
const tar2 = {b:2,c:2};
const tar3 = {c:3}
Object.assign(tar, tar2, tar3);
console.log(tar);//{a:1,b:2,c:3}
Object.assign(undefined,{a:1});
var test = Object.assign(1,{a:1});
console.log(test);//Number{1,a:1}
var test = Object.assign({a:1},'123');
log(test);
0: "1"
1: "2"
2: "3"
a: 1
如果第二个参数为boolean和number类型的都输出{}
var test = Object.assign([1,2,3,4],123);
var test = Object.assign([1,2,3,4],'321');
Object.create(proto[, propertiesObject])
可选。如果没有指定为 undefined,则是要添加到新创建对象的不可枚举(默认)属性(即其自身定义的属性,而不是其原型链上的枚举属性)对象的属性描述符以及相应的属性名称。这些属性对应Object.defineProperties()的第二个参数。
var obj = Object.create({foo:1},{
bar:{
value:2
},
baz:{
value:3,
enumberable:true
}
})
log(obj)//
{
baz:3
bar:2
__proto__:
foo:1
}
//原型上的属性不管可不可以枚举的都不能拷贝
var copy = Object.assign({},obj);
log(copy);//{baz:3}
可以生成不相等的原始值
var a = symbol();
var b = symbol();
log(a === b);//打印false
var a = symbol('a');
var b = symbol('a')
log(a == b)//打印false
拷贝
var test = Object.assign({a:'b'},{[Symbol('c')]:'d'});
log(test);
//{a:"b",Symbol(c):"d"}
const obj1 = {a:{b:1}};
const obj2 = Object.assign({},obj1);
obj1.a.b = 2;
log(obj2);//{a:{b:2}}
const target = {a:{b:'c',d:'e'}};
const sourse = {a:{b:'hello'}};
Object.assign(target, sourse);
log(target);//{a:{b:hello}}
var age = 1;
function Person(){}
Object.assign(Person.prototype,{
eat(){
},
age
})
log(Person.prototype);
//{age:1,eat:eat()}
默认参数
通过三个参数来实现
const DEFAULT = {
url: {
host: 'www.baidu.com',
port: 7070
}
}
function test(option){
option = Object.assign({},DEFAULT,option);
log(option)
}
不传参
test();//{url:{host:'www.baidu.com',port:7070}}
传参
test({url:{port:8080}})//{url:{host:'www.baidu.com',port:8080}}
(6).defineProperties()/getOwnPropertyDescriptors()
var obj = {}
Object.defineProperties(obj,{
a:{
value: true,
writable: true
},
b:{
value: 'hello',
writable: false
}
})
log(Object.getOwnPropertyDescriptors(obj));
//{
a:
configurable: false
enumerable: false
value: true
writable:true
}
//{
b:
configurable: false
enumerable: false
value: 'hello'
writable:true
}
var obj = {a:1, b:2, c:3}
const clone = Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj))
log(clone) {a:1,b:2,c:3}
/优化写法
const clone = (obj) => Object.create(Object.getPrototypeOf(obj),Object.getOwnPropertyDescriptors(obj))
1.const obj = Object.create(prot);
2.const obj = Object.assign(Object.create(prot),{
3.const obj = Object.create(prot,Object.getOwnPropertyDescriptors({