深入理解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希望大家能够喜欢,转发并并点赞就是对我最大的支持,也是我写后续文章的动力,谢谢大家。
未完待续。。。。
共同学习,写下你的评论
评论加载中...
作者其他优质文章