本系列博客为ES6基础语法的使用及总结,若有错误,欢迎指正。
重学ES6之出来混早晚要还的(一)主要包括 var、let、const变量声明 和 箭头函数相关 。面试
其余笔记:
重学ES6之出来混早晚要还的(二)
重学ES6之出来混早晚要还的(三)
重学ES6之出来混早晚要还的(四)
重学ES6之出来混早晚要还的(五)
重学ES6之出来混早晚要还的(六)
数据类型的转换/判断/比较segmentfault
var
的使用1.基本用法
1.1 定义变量格式:var 变量名称 = 变量值
,若是没有给变量赋值,默认为undefined
1.2 用 var 声明的变量的做用域是它当前的执行上下文,它能够是嵌套的函数,也能够是声明在任何函数外的变量。
1.3 经过var定义变量,能够重复定义同名变量,不会报错;后定义的会覆盖先定义的。
1.4 经过var定义在{}(块级做用域)的变量,不区分全局变量和局部变量,后续仍可使用。
1.5 经过var定义变量,能够先使用后定义(预解析)数组
//定义一个变量 var a; //重复定义同名变量 var a = 18; var a = 16; console.log(a); //输出16
2.变量提高(hoisting)
2.1 经过var声明的变量能够在声明以前使用,输出undefined(也就是咱们常说的能够先使用后定义)
2.2 这个行为叫作“hoisting”,也就是咱们说的预解析。把全部的变量声明移动到函数或者全局代码的开头位置。浏览器
console.log(a); //输出undefined var a = 18 //预解析以后 var a; console.log(a); //输出undefined a = 18
3.注意点
3.1 经过var声明的变量属于函数做用域,若是当前没有函数,则属于全局做用域。在外界是能够访问到的。app
var price = 10; var count = 10; if(count > 5){ var discount = price * 0.8; //discount是一个全局变量,在控制台能够访问到 console.log(`the discount is ${discount}`); }
若是换成let定义:经过let定义的discount是一个局部变量,在控制台不能够访问函数
var price = 10; var count = 10; if(count > 5){ let discount = price * 0.8; console.log(`the discount is ${discount}`); }
3.2 window对象上有一个叫作name的属性,若是使用var定义一个叫作name的属性,那么就会覆盖掉window的name属性。this
var name = "mss";
解决:能够经过当即执行函数(IIFE (Immediately Invoked Function Expression) ),使变量私有化,避免属性重写的问题。此时输出的name就是window上面的name属性。spa
可是,利用当即执行函数仅仅为了声明一个变量,避免变量重写有点大材小用了...请避免这样的用法prototype
(function () { var name = 'mss'; console.log(name); })()
let
的使用1.基本用法
1.1 经过let不能够重复定义同名变量。
1.2 经过let定义变量,不能够先使用再定义,浏览器不会对let定义的变量进行预解析。会输出ReferenceError
1.3 经过let定义在{}的变量区分全局变量和局部变量
1.4 经过let定义在{}的局部变量,只能在{}中使用,后续不可使用,只在块级做用域内有效。code
//不能够先使用再定义 console.log(a); //ReferenceError let a = 18; //不可重复定义 let a = 18; let a = 88; console.log(a); //Identifier 'a' has already been declared //块级做用域内区分全局变量和局部变量 { let a = 18; //局部变量 var person = 'jelly'; //全局变量 console.log(a); //18 } console.log(a); //ReferenceError console.log(person); //jelly
2.注意点
2.1 let不会在全局声明时(在最顶部的范围)建立window 对象的属性。
在程序和方法的最顶端,let不像 var 同样,let不会在全局对象里新建一个属性。
位于函数或代码顶部的var声明会给全局对象新增属性, 而let不会。例如:
var x = 'global'; let y = 'global'; console.log(this.x); // "global" console.log(window.x); // "global" console.log(this.y); // undefined console.log(window.y); // undefined
2.2 在同一做用域内经过let定义变量,毫不容许同名变量出现;包括用var声明的变量。
{ let name = "jelly"; var name = "vicky"; //Identifier 'name' has already been declared } let name = "jelly"; { var name = "vicky"; //Identifier 'name' has already been declared } { let name = "jelly"; { let name = "vicky"; //不报错 } }
3.暂时性死区(TDZ(Temporal dead zone))
与经过 var 声明的有初始化值 undefined 的变量不一样,经过 let 声明的变量直到它们的定义被执行时才初始化。在变量初始化前访问该变量会致使 ReferenceError
。该变量处在一个自块顶部到初始化处理的“暂存死区”中。
4.一道很切题的题
var a = 5; //var定义的a绑定到了window对象上面 let obj = { a: 10, foo: function () { console.log(this.a); } }; let bar = obj.foo; obj.foo(); //10 obj调用了foo函数,this就是obj对象,输出10 bar(); //5 bar函数是输出当前对象(window)上面的a,为5 let a = 5; //let定义的a不会绑定到window对象上面 let obj = { a: 10, foo: function () { console.log(this.a); } }; let bar = obj.foo; obj.foo(); //10 obj调用了foo,this就是obj对象,输出10 bar(); //undefined 当前的this是window对象,可是window上面没有a属性,输出undefined
一道奇怪写法的笔试题
var a = 5; function test() { a = 0; console.log(a); //0 console.log(this.a); //undefined var a; console.log(a); //0 } new test();
上例中,在函数内声明变量a=0
,在后面又使用var a
,会进行变量提高,因此在函数内部就存在一个局部变量a了,因此两次console.log(a)
都输出0;console.log(this.a)
输出undefined能够理解为没有东西调用test函数,致使this的指向不明确,也就找不到this.a属性。
const
的使用1.用法
1.1 const 用于声明一个或多个常量,常量的值不可改变。例如亘古不变的PI,能够用const定义。
1.2 const定义常量与使用let 定义的变量有着惊人的类似之处:
var x = 10; { const x = 2; console.log(x); //2 } console.log(x); //10
1.3 二者还有如下两点区别:
// 错误写法 const PI; PI = 3.14159265359; // 正确写法 const PI = 3.14159265359;
2.const用法之面试现场还原
使用 const 定义的对象或者数组,实际上是可变的。对象的引用(地址)不可更改,可是对象的属性能够改变;只是咱们不能对常量对象从新赋值
// 建立常量对象 const car = {type:"Fiat", model:"500", color:"white"}; // 修改属性: car.color = "red"; // 合法 // 添加属性 car.owner = "Johnson"; // 合法 const car = {type:"Fiat", model:"500", color:"white"}; car = {type:"Volvo", model:"EX60", color:"red"}; // 错误
var
,let
,const
的使用场景const
by default)let
if rebinding is needed)var
shouldn't be used in ES6)//没有参数 () => {函数声明} //一个参数 单一参数 => {函数声明} //多个参数 (参数1, 参数2, …, 参数N) => { 函数声明 }
什么是显示返回?
显示返回格式:return “返回的内容”
2.1.1 箭头函数的隐式返回:
const arr = [2,4,6,8,10]; const double = arr.map(function (number) { return number *2; }); console.log(double); //等价于 const double2 = arr.map((number) => number*2); console.log(double2);
2.1.2 注意:箭头函数都是匿名函数,若是想要经过命名函数的方式使用箭头函数,通常把箭头函数赋值给一个变量便可
const greet = name => console.log(`hello ${name}`); greet("mss");
例1:
let p = { name: "lnj", say: function () { console.log(this); }, hi: () => { console.log(this); } }; p.say(); //object p.hi(); //window
例2:
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { //console.log(this); //this是person这个对象 this.hobbies.map(function (hobby) { //console.log(this);//this是window console.log(`${this.name} loves ${hobby}`); }) } }; person.output(); /* 输出结果: loves money loves sleeping loves eating */
上述例子中能够看出,并无输出name属性。在output的函数中,this指向person这个对象,而map方法的回调函数是一个独立的函数,一个独立函数运行的时候,没有做为对象的方法调用或者没有使用call等修改this的值时,则此时this指向window;
过去的作法是:在外面保存一下this
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { let that = this; this.hobbies.map(function (hobby) { console.log(`${that.name} loves ${hobby}`); }) } }; person.output(); /* 输出结果 mss loves money mss loves sleeping mss loves eating */
2.2.1 解决:在ES6中能够用箭头函数来解决这种问题
2.2.2 缘由:
const person = { name: 'mss', hobbies: ['money','sleeping','eating'], output: function () { this.hobbies.map(hobby => { console.log(`${this.name} loves ${hobby}`); }) } }; person.output(); /* 输出结果 mss loves money mss loves sleeping mss loves eating */
2.2.3 应用:函数节流/防抖中使用箭头函数简化代码
//防抖 function debounce(fn,delay) { let timerId = null; return function (...args) { timerId && clearTimeout(timerId); timerId = setTimeout(()=>{ fn.apply(this,args); },delay || 3000); } } //节流 function throttle(fn,delay) { let timerId = null; let flag = true; return function (...args) { if(!flag) return; flag = false; timerId && clearTimeout(timerId); timerId = setTimeout(()=>{ flag = true; fn.apply(this,args); },delay || 3000); } }
箭头函数不绑定Arguments 对象,即箭头函数没有Arguments对象。
3.1 做为构造函数或者是一个对象的方法或者给原型绑定方法的时候,是不容许使用箭头函数的
箭头函数没有prototype属性。
let Foo = (name,age) => { this.name = name; this.age = age; }; let foo = new Foo('ghk',22); // TypeError: Foo is not a constructor Foo.prototype.say = () => { console.log(`hello ${this.name}`); // TypeError: Foo is not a constructor }
3.1.1 缘由:经过new生成一个实例的时候,在内部会完成四个步骤
(1)建立一个新的对象
(2)将构造函数中的做用域赋值给新对象(构造函数的this就指向了该新生成的对象)
(3)执行构造函数中的代码(为新对象添加属性)
(4)返回新对象
箭头函数用做构造器时,并未完成把this值绑定到新生成的对象上面去这个步骤,因此会报错,所以只能使用原始函数做为构造函数。
正确写法:
let Foo = function(name,age){ this.name = name; this.age = age; }; let foo = new Foo('ghk',22); Foo.prototype.say = function (){ console.log(`hello ${this.name}`); }; foo.say();
3.2 须要使用this的时候(交互的时候),不推荐使用箭头函数
给元素绑定事件时,不可用箭头函数。由于此时箭头函数的this是window,而触发事件this应该指向到触发事件的该元素上。
错误写法:
let oBtn = document.querySelector(".btn"); oBtn.addEventListener("click",() => { console.log(this); //this是window,因此会报错 this.classList.add("in"); setTimeout(() => { console.log(this); //this是oBtn this.classList.remove("in"); },2000) })
正确写法:
let oBtn = document.querySelector(".btn"); oBtn.addEventListener("click",function () { console.log(this); //this是oBtn this.classList.add("in"); setTimeout(() => { console.log(this); //this是oBtn this.classList.remove("in"); },2000) })
3.3 须要使用Arguments对象的时候,不推荐使用箭头函数
箭头函数中没有Arguments对象
错误写法:
let sum = () =>{ return Array.from(arguments) .reduce((prevSum,curValue) => prevSum + curValue); }; sum(1,2,3); //arguments is not defined
正确写法:
let sum = function(){ return Array.from(arguments) .reduce((prevSum,curValue) => prevSum + curValue); }; console.log(sum(1, 2, 3)); //6
或者:
let sum = (...args) => { return args.reduce((prevSum,curValue) => prevSum + curValue); }; console.log(sum(1, 2, 3));
3.4 不可使用 yield
命令,所以箭头函数不能用做Generate函数。
补充知识
注:Array.from()
做用是把类数组对象转换为真数组
Array.from(arrayLike[, mapFn[, thisArg]])
console.log(Array.from('foo')); // expected output: Array ["f", "o", "o"] console.log(Array.from([1, 2, 3], x => x + x)); // expected output: Array [2, 4, 6]
注:reduce()
为数组中的每个元素依次执行callback函数,不包括数组中被删除或从未被赋值的元素
arr.reduce(callback(accumulator, currentValue[, index[, array]])[, initialValue])
let arr = [1,2,3,4]; let sum = (accumulator,currentValue) => accumulator + currentValue; console.log(arr.reduce(sum)); //10 console.log(arr.reduce(sum, 5)); //15
上面的代码中,sum函数的参数accumulator是累积变量,参数currentValue是当前的数组成员。每次执行时,currentValue会加到accumulator,最后输出accumulator。
reduce方法中的第二个参数不传的时候,初始值默认使用数组中的第一个元素。即1+2+3+4输出10;当初始值为5时,即5+1+2+3+4输出15.
本文章参考到的连接:
https://developer.mozilla.org...
http://www.ruanyifeng.com/blo...
https://www.runoob.com/