拓展-6【es6新增语法与api小结-未完待续】

一.基础

es5发布于2009年 其实用的是99年发布的ecma3.0改进的3, es6发布于15年

babel进行es6的转译编码但是不能转译api 可以通过babel-polyfill进行转译

在线转码工具有babel 和 traceur两种

二.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()//这样又会报错

也就是说小括号里可以访问到外面的作用域

大括号里如果声明let 也会报错

(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都能进行隐式转换

可以通过结构来访问被结构对象的函数

un / null 是不能进行隐式转换的

let {prop} = null;
log(prop);

函数中加入es6默认值对length的影响

首先会造成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实效

其次会导致arguments失效

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

与sort结合示例

var arr = [123,12,31,23,1,4,4213,3213,43];
var arr1 = arr.sort((a,b) => a - b)
即可排序

箭头函数中没有arguments

箭头函数的实质

1.this.为外层的函数作用域来决定(箭头函数的作用域是父级的作用域,而不是父级)

2.=>不能作为构造函数来使用

3.没有arguments对象,用rest(拓展运算符)

4.yield 命令不能生效,在generator函数中

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}

argument坑

function foo(){
    setTimeout(()=>{
        log(arguments);//1234567
    })
}
foo(1,2,3,4,5,6,7)//这里拿的是父级的arg

总结:箭头函数应用于没有递归,执行语句较少,不需要需要引用函数名,不需要实例化的时候

(2).rest

rest运算符有两种用法

收集

收集多数用在形参上,可以将传入的值变为数组,但是收集必需是最后一个参数

//将值收集为数组
var sum = (...args) =>{
    log(args[0]+args[1])
}
sum(1,2)

//收集必需是最后一个参数
let fn =(a,b,c,...d) =>{}

展开

可以将数组展开为, xx,xx的形式

//将数字展开为各个值
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时去改值就会静默失败

要阻止删除要把configurable设置为false

(2).getter/setter

get

伪属性

重写了属性获取的,这就叫做伪属性

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

同时还可以与defineProperty结合

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也会和defineProperty发生冲突

在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
})//会报错

set

get和set一般都是成对出现的

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
})

密封方式二defineProperty

通过defindproperty配置描述符全部为false

密封方式三seal/isSealed

var obj = {a : 2};
Object.seal(obj); 
console.log(Object.isSealed(obj))//true
没有被密封 底层把所有的configurable改为false

密封方式四freeze/isFrozen

这也是级别最高的密封

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])
        }
    }
}

总结:

共有四种方式冻结

1.defineProperty

2.preventExtensions

3.seal

5.freeze

(4).is

解决了NAN和+0 -0的问题

log(+0 === -0);//true
log(NaN === NaN);//false
log(Object.is(NaN,NaN))//true
log(Object.is(+0,-0))//false

(5).assign对象合并

assign合并一个对象

(1).基础

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返回的对象就是原对象

(2).合并和覆盖的情况

合并
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}

(3).第一个参数为原始值

无法进行合并因为没有包装类 null也是一样

Object.assign(undefined,{a:1});

有包装类的调用

var test = Object.assign(1,{a:1});
console.log(test);//Number{1,a:1}

(4).第二个参数为原始值

判断第二个值是否可枚举,然后合并

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);

console.log(test);[1,2,3,4]

var test = Object.assign([1,2,3,4],'321');

console.log(test);

["3", "2", "1", 4]

(5).取值函数拷贝

Object.create

Object.create(proto[, propertiesObject])

参数

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}

(6).symbol拷贝

可以生成不相等的原始值
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"}

(7).assign是浅拷贝

浅拷贝

证明assign是浅拷贝

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}}

(8).原型扩充

var age = 1;
function Person(){}
Object.assign(Person.prototype,{
    eat(){
        
    },
    age
})
log(Person.prototype);
//{age:1,eat:eat()}

(9).默认参数

默认参数
通过三个参数来实现
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
}

浅拷贝优化

Object.getPrototypeOf(obj)

方法返回指定对象的原型

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);

obj.foo = 123;

2.const obj = Object.assign(Object.create(prot),{

foo: 123

})

3.const obj = Object.create(prot,Object.getOwnPropertyDescriptors({

foo:123

}))

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值