深入理解es6(一)

前言

对于es6大多数人都了解,但是好多东西理解的不是很深刻,下面就我个人在用es6的过程中对es6的理解,把es6和es5进行对比讲解,希望大家能够喜欢。今天我们主要介绍块级绑定、字符串方法、函数,还有好多es6的东西,会慢慢和大家一起理解。

目录

  • 块级绑定(let和const)
  • 字符串方法
  • 函数

块级绑定(let和const)

var声明与变量提升,看下边这个例子

function fn(flag) {    
  if (flag) {        
        var a = 1;    
   }     
   console.log(a); //undefined
}
fn(false);复制代码

如果你不太熟悉 JS, 或许会认为仅当 condition 的值为 true 时, 变量 value 才会被创
建。 但实际上, value 无论如何都会被创建, 就像下边这样

function fn(flag) {
    var a;
    if (flag) {
        a = 1;
    }
    console.log(a); //undefined
}
fn(false);
复制代码

这就是变量提升
而let和const就不会造成变量提升, 这就是块级声明, 只会在一个代码块中被创建或者在一个函数内部。

1.变量声明let

function fn(flag) {
    if (flag) {
        let a = 1;
    }
    console.log(a); // 会报错a is not defined
}
fn(true) 复制代码

如上边代码一样只要传的值不为true则a永远不会被创建。

2.禁止重复声明

var a = 1;let a = 1;复制代码

如果已经声明过一个a底下再次声明会报一个错误Identifier 'a' has already been declared,向下边这样写没问题

var a = 1;
if (flag) {
    let a = 1;
}复制代码

这是因为if判断是一个代码块而在这里声明的a只能在if中用

3.常量声名const

const a = 1;
const b;//抛出错误Missing initializer in const declaration复制代码

第二个声明的b就会报错, 因为没有赋值。
另外常量const声明的值不能更改例如:

const a = 1;
a = 2; //抛出错误Assignment to constant variable.
复制代码

const声明与let 声明一样, 都是块级声明。 这意味着常量在声明它们的语句块外部是无法访
问的, 并且声明也不会被提升,cosnt声明的对象也不可以更改

cosnt obj = {
        a: 1    
}
//允许这样修改
obj.a = 2
//不允许这样修改
obj = {    a: 2}复制代码

他们两个有个共同的缺点叫做暂时性死区

if (true) {
    console.log(typeof value); //抛出错误 value is not defined
    let value = "blue"
}复制代码

因为在此之前并没有叫做value的变量, 改成const也一样

4.循环中的块级绑定

for (var i = 0; i < 5; i++) {
    process(arr[i]) 
}
console.log(i) //5复制代码

把var改为let

for (let i = 0; i < 5; i++) {
    process(arr[i]) 
}
console.log(i) //抛出错误没有i复制代码

变量 i 仅在 for 循环内部可用,一旦循环结束,该变量在任意位置都不可访问

5.循环中的函数

var funcs = [];
for (var i = 0; i < 10; i++) {
    funcs.push(function() {
     console.log(i) 
    })
}
funcs.forEach(function(func) {
    func()
}); // 输出数值 "10" 十次复制代码

原本以为会输出0 - 9, 就是因为i每一次的值都是10, 所以才会打印出十次10可以这样改进

var funcs = [];
for (var i = 0; i < 10; i++) {
    funcs.push(function(value) { 
       return function() {
            console.log(value)
        }
    }(i))
}
funcs.forEach(function(func) {
    func()
});复制代码

或者使用let, 不能使用const, 因为cosnt的值每次都不能改变

var funcs = [];
for (let i = 0; i < 10; i++) {
    funcs.push(function() {
        console.log(i)
    })
}
funcs.forEach(function(func) {
    func()
})复制代码

在我们使用for in 或者for of 的时候都可以使用let声明变量
let 与const 不同于var 的另一个方面是在全局作用域上的表现。

var a = 'hi';console.log(window.a) //hi
console.log(window.a == a) //ture
let a = 'hi';
console.log(a) //hi
console.log(window.a === a) //false;复制代码

字符串方法

1.odePointAt与fromCodePoint

codePointAt() 可以按位数提取unicode代码

coonst text = '哈哈';
console.log(text.codePointAt(0)) //21704复制代码

fromCodePoint() 与codePointAt() 相反可以产生单个字符串

console.log(String.fromCodePoint('21704')) //哈复制代码

2.includes() 与startsWith(), endsWith();
includes() 如果字符串中有这个字符就返回true否则返回false有两个传参数, 第一个是找哪个字符第二个从哪找默认是从开头第一个找
startsWith() 从字符串开头找某个字符, 如找到就返回true否则返回false, 有两个传参数, 第一个是找哪个字符第二个从哪找默认是从开头第一个
endsWith() 与startsWith() 相反从字符串结尾找某个字符, 如找到就返回true否则返回false, 有两个传参数, 第一个是找哪个字符第二个从哪找默认是从结尾第一个

var msg = "Hello world!";
console.log(msg.startsWith("Hello")); // true
console.log(msg.endsWith("!")); // true
console.log(msg.includes("o")); // true
console.log(msg.startsWith("o")); // false
console.log(msg.endsWith("world!")); // true
console.log(msg.includes("x")); // false
console.log(msg.startsWith("o", 4)); // true
console.log(msg.endsWith("o", 8)); // true
console.log(msg.includes("o", 8)); // false
复制代码

3.repeat()

repeat() 接受一个值这个值就是字符串重复的次数

 'x'.repeat(3) //'xxx'
复制代码

前边字符串加空格缩进可以这样写

' '.repeat(4); //'    '复制代码

4.模板字面量

使用 ``包裹字符串

var a = `a` //a复制代码

如果想用字符串中的 ``直接用\ 转义就行

5.多行字符串

之前字符串如果是多行的话只能使用 + 拼接, 现在可以使用\

var a = 'a b ' //会报错var a = 'a\b' //'a b' 使用``也是一样复制代码

6.$符

javascript到了es6也引入了$, 说明我们也跟钱挂钩了, 其实$ {}

是和 ``一起用的$ {}里边可以声明变量

var a = '张三';`name: ${a}` //name: 张三复制代码

函数

1.函数默认值
es5中函数默认值是判断有没有这个值有的话就用传入的值没有给他赋值

function fn(num) {
    num = num || 1;
}复制代码

上边的写法一般的字符串还可以如果传入的是0就会走默认值, 所以我们要把上边的方法改造一下

function fn(num) {
    num = (typeof num !== 'undefined' ? num : 1);
}复制代码

es6里引入了直接可以给参数赋值, 如果没有传这个参数, 就用默认的值

function fn(num = 1) {
    return num;
}
console.log(fn(2)) //2
console.log(fn()) //1复制代码

2.参数默认值如何影响arguments 对象

function mixArgs(first, second) {
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs("a", "b")    // true true true true复制代码

在非严格模式下, arguments 对象总是会被更新以反映出具名参数的变化。 因此当 first
与 second 变量被赋予新值时, arguments[0] 与 arguments[1] 也就相应地更新了, 使得这
里所有的 === 比较的结果都为 true。
然而在 ES5 的严格模式下, 关于 arguments 对象的这种混乱情况被消除了, 它不再反映出
具名参数的变化。 在严格模式下重新使用上例中的函数:

function mixArgs(first, second) {
    "use strict"; 
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d"; 
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs("a", "b");//true true false false复制代码

然而在使用 ES6 参数默认值的函数中, arguments 对象的表现总是会与 ES5 的严格模式一致

function mixArgs(first, second = "b") {
    console.log(arguments.length);
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
    first = "c";
    second = "d";
    console.log(first === arguments[0]);
    console.log(second === arguments[1]);
}
mixArgs("a")    //1 true false false false false false复制代码

3.不具名参数

es5不具名参数

function pick(object) {
    let result = {};
    // 从第二个参数开始处理
    for (let i = 1, len = arguments.length; i < len; i++) {
        result[arguments[i]] = object[arguments[i]];
    }    
    return result;
}
let book = {
    title: "Understanding ES6",
    author: "Nicholas C. Zakas",
    year: 2015
};
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "Nicholas C. Zakas"
console.log(bookData.year); // 2015复制代码

因为arguments接受了三个值咱们遍历是从第二个值开始的也就拿的是咱们穿的两个字符串, 声明了一个空的对象, 遍历之后给这个空对象重新赋值, 然后返回这个对象。
es6引入了剩余参数就解决了这个问题, 可以直接传多个参数,剩余参数...

function pick(object, ...keys) {
    let result = {};
    for (let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];
    }
    return result;
}
let bookData = pick(book, "author", "year");
console.log(bookData.author); // "Nicholas C. Zakas"
console.log(bookData.year); // 2015复制代码

因为...keys接受了剩余的两个个值咱们直接遍历keys就可以了, 声明了一个空的对象, 遍历之后给这个空对象重新赋值, 然后返回这个对象。
剩余参数受到两点限制。 一是函数只能有一个剩余参数, 并且它必须被放在最后。

function pick(object, ...keys, last) {
    let result = Object.create(null);
    for (let i = 0, len = keys.length; i < len; i++) {
        result[keys[i]] = object[keys[i]];    
    }
    return result;
} //报错复制代码

4.es6还增强了函数构造器的能力

var add = new Function("first", "second", "return first + second");
console.log(add(1, 1)); // 2复制代码

Function 构造器允许你动态创建一个新函数, 不常用, 同时也可以使用es6的剩余参数和赋默认值
5.扩展运算符
剩余参数允许你把多个独立的参数合并到一个数组中; 而扩展运算符则允许将一个数组分割, 并将各个项作为分离的参数传给函数

let value1 = 25,
    value2 = 50;
console.log(Math.max(value1, value2)); // 50复制代码

处理两个值可以使用Math.max(), 但是处理数组就要搜索整个数组, es5可以使用apply, es6可以使用扩展运算符

let values = [25, 50, 75, 100]
console.log(Math.max.apply(Math, values)); // 100
// 等价于 
console.log(Math.max(25, 50, 75, 100));
console.log(Math.max(...values)); // 100复制代码

6.名称属性

匿名函数表达式的流行使得调试有点困难, 经常导致堆栈跟踪难以被阅读与解释。

function doSomething() {
    // ...
}
var doAnotherThing = function() {
    // ...
};
console.log(doSomething.name); // "doSomething"
console.log(doAnotherThing.name); // "doAnotherThing"复制代码

7.函数的双重用途

ES5 以及更早版本中, 函数根据是否使用 new 来调用而有双重用途。 当使用 new 时,函数内部的 this 是一个新对象, 并作为函数的返回值

function Person(name) {
    this.name = name;
}
var person = new Person("Nicholas");
var notAPerson = Person("Nicholas");
console.log(person); // "[Object object]"
console.log(notAPerson); // "undefined"·复制代码

当创建 notAPerson 时, 未使用 new 来调用 Person(), 输出了 undefined Person 首字母大写是指示其应当使用 new 来调用的唯一标识, 这在 JS 编程中十分普遍。 函数双重角色的混乱情况在 ES6 中发生了一些改变。
es5使用instanceof判断函数如何被调用

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");var notAPerson = Person("Nicholas");复制代码

此处对 this 值进行了检查, 来判断其是否为构造器的一个实例: 若是, 正常继续执行; 否则抛出错误。 该方法并不绝对可靠, 因为在不使用 new 的情况下 this 仍然可能是 Person 的实例。

function Person(name) {
    if (this instanceof Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
var person = new Person("Nicholas");
var notAPerson = Person.call(person, "Michael"); // 成功了!复制代码

因为调用 Person.call() 并将 person 变量作为第一个参数传入, 这意味着将 Person 内部的
this 设置为了 person。
为了解决这个问题es6有个new.target元属性

function Person(name) {
    if (new.target === Person) {
        this.name = name; // 使用 new
    } else {
        throw new Error("You must use new with Person.")
    }
}
function AnotherPerson(name) {
    Person.call(this, name);
}
var person = new Person("Nicholas");
var anotherPerson = new AnotherPerson("Nicholas"); // 出错!复制代码

8.箭头函数
  • 没有 this、 super、 arguments, 也没有 new.target
  • 不能被使用 new 调用
  • 没有原型
  • 不能更改 this
  • 不允许重复的具名参数
语法

var reflect = value => value;
// 有效等价于:
var reflect = function(value) {
    return value;
};复制代码

不传值的函数

var getName = () => "Nicholas";
// 有效等价于:
var getName = function() {
    return "Nicholas";
};复制代码

空函数

var doNothing = () => {};
// 有效等价于:
var doNothing = function() {};复制代码

但若箭头函数想要从函数体内向外返回一个对象字面量就必须将该字面量包裹在圆括号内

var getTempItem = id => ({ id: id, name: "Temp" });
// 有效等价于:
var getTempItem = function(id) {
    return {
        id: id,
        name: "Temp"
    };
};复制代码

立即调用箭头函数

let person = ((name) => {
    return {
        getName: function() {
            return name;
        }
    };
})("Nicholas");
console.log(person.getName()); // "Nicholas"复制代码

识别箭头函数

var comparator = (a, b) => a - b;
console.log(typeof comparator); // "function"
console.log(comparator instanceof Function); // true复制代码

箭头函数可以使用 call()、 apply() 与 bind() 方法

var sum = (num1, num2) => num1 + num2;
console.log(sum.call(null, 1, 2)); // 3
console.log(sum.apply(null, [1, 2])); // 3
var boundSum = sum.bind(null, 1, 2);
console.log(boundSum()); // 3复制代码

这篇es6希望大家能够喜欢,转发并并点赞就是对我最大的支持,也是我写后续文章的动力,谢谢大家。

未完待续。。。。



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值