Skip to content

ES6

块级作用域

  • 什么是块级作用域

简单说一个{}计时一个块级作用域,常见的开机作用域有函数,循环,{}

  • 为什么需要块级作用域
    • var变量 会提升 提升到函数体的最前面
    • 同名局部变量会覆盖全局变量
    • 循环都结束了,但是循环变量还可以使用
      js
        // 我们希望循环结束后,循环变量是不能使用的
        for (var i = 0; i <= 10; i++) {
        console.log("i=", i);
        }
        console.log("------");
        console.log("last i=", i);
        // 我们希望循环结束后,循环变量是不能使用的
        for (var i = 0; i <= 10; i++) {
        console.log("i=", i);
        }
        console.log("------");
        console.log("last i=", i);
if判断的{}内属于块级作用域
js
// t是一个全局变量
// let t = "hello es6"
// console.log(t);

; (function () {
    // 即使使用了var  但是var t 是写在函数中的
    // 形成局部作用域,不会污染全局
    var t = "hello es6"
    console.log(t);
}())

var t = 666;
console.log(t);
// t是一个全局变量
// let t = "hello es6"
// console.log(t);

; (function () {
    // 即使使用了var  但是var t 是写在函数中的
    // 形成局部作用域,不会污染全局
    var t = "hello es6"
    console.log(t);
}())

var t = 666;
console.log(t);

暂存性死区

js
let t = "hello";

{
    // {} + let已经形成了块级作用域
    // let 是不能提升的
    // ReferenceError: Cannot access 't' before initialization
    // 暂存性死区
    console.log("t=", t);
    let t = "world";
}
let t = "hello";

{
    // {} + let已经形成了块级作用域
    // let 是不能提升的
    // ReferenceError: Cannot access 't' before initialization
    // 暂存性死区
    console.log("t=", t);
    let t = "world";
}

let const

相同点

  • let、const定义的变量/常量不会提升
  • 暂存性死区
js
if(true){
    // ReferenceError: Cannot access 'num' before initialization
    num = 888;  // 把888赋值给num  找num  只能在自己的作用域中找
    // 在使用let声明变量之前,不能使用这个变量,在之前的这一片区域,叫暂时性死区
    // 说白了,使用let声明变量之前,该变量不能使用。
    let num; // let + {}形成块给作用域  num说白了,是局部变量
}
if(true){
    // ReferenceError: Cannot access 'num' before initialization
    num = 888;  // 把888赋值给num  找num  只能在自己的作用域中找
    // 在使用let声明变量之前,不能使用这个变量,在之前的这一片区域,叫暂时性死区
    // 说白了,使用let声明变量之前,该变量不能使用。
    let num; // let + {}形成块给作用域  num说白了,是局部变量
}
  • 不允许重复声明
  • 使用let、const声明的变量,并不会挂载到GO上的

不同点

  • let 声明变量, const 声明常量
  • const 声明是必须赋初值,且不允许修改
js
const声明的常量
const PI = 3.14;
PI = 666;
// TypeError: Assignment to constant variable.
console.log(PI);
const声明的常量
const PI = 3.14;
PI = 666;
// TypeError: Assignment to constant variable.
console.log(PI);

ts开发同通过as const让变量、对象变为只读

ts
const obj = {
  name: 'John',
  age: 30,
} as const;

obj.name = 'Alice'; // Error: 无法分配到 "name" ,因为它是只读属性。
const obj = {
  name: 'John',
  age: 30,
} as const;

obj.name = 'Alice'; // Error: 无法分配到 "name" ,因为它是只读属性。

结构解析赋值

数组结构解析赋值

  • 结构解析赋值要保证两侧的数据类型要一样
js
let [name1,name2,name3] =  ["wc", "xq", "jj"];
console.log(name1,name2,name3);
let [name1,name2,name3] =  ["wc", "xq", "jj"];
console.log(name1,name2,name3);
ts
let [
    {
        userName,
        age
    },
    [num1, num2],
    num3
] = [
  {
    userName: 'zs',
    age: 18
  },
  [1, 3],
  6
];
console.log(userName, age, num1, num2, num3);
let [
    {
        userName,
        age
    },
    [num1, num2],
    num3
] = [
  {
    userName: 'zs',
    age: 18
  },
  [1, 3],
  6
];
console.log(userName, age, num1, num2, num3);
  • 如果解构不成功,对应的值是und
ts
let [num1, num2] = [666];
console.log(num1, num2); // 666 und
let [num1, num2] = [666];
console.log(num1, num2); // 666 und
  • 如果解析不成功,可以指定默认值
ts
const [a = 5, b = 4, c, d = 88] = [66, 77]
//a:66 b:77 c:und d:88
const [a = 5, b = 4, c, d = 88] = [66, 77]
//a:66 b:77 c:und d:88
  • 不完全解构
ts
let [,b,] = ['周星驰','吴孟达','王宝强'];
console.log(b);// 吴孟达
let [,b,] = ['周星驰','吴孟达','王宝强'];
console.log(b);// 吴孟达
  • 结合reset运算符解析
ts
let [a,...b] = ['周星驰','吴孟达','王宝强'];
console.log(a,b);// '周星驰' ['吴孟达','王宝强'];
// let [...a] = ['周星驰','吴孟达','王宝强']; // ['周星驰','吴孟达','王宝强']
let [a,...b] = ['周星驰','吴孟达','王宝强'];
console.log(a,b);// '周星驰' ['吴孟达','王宝强'];
// let [...a] = ['周星驰','吴孟达','王宝强']; // ['周星驰','吴孟达','王宝强']

提示

rest 元素必须位于最后

ts
let [...a,b] = ['周星驰','吴孟达','王宝强'];
let [...a,b] = ['周星驰','吴孟达','王宝强'];

使用结构解析赋值交换两个变量

ts
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b); // 2 1
let a = 1;
let b = 2;
[a,b] = [b,a];
console.log(a,b); // 2 1

展开运算符和reset运算符

  • 展开运算符
ts
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [...arr1, ...arr2]
console.log(arr3);// [1,2,3,4,5,6]
let arr1 = [1, 2, 3];
let arr2 = [4, 5, 6];
let arr3 = [...arr1, ...arr2]
console.log(arr3);// [1,2,3,4,5,6]
  • reset运算符
ts
let [a,...b] = ['周星驰','吴孟达','王宝强'];
console.log(b); // ['吴孟达','王宝强']
function fn(a,...args) {
  console.log(typeof  args, args instanceof Array) // object true
  console.log(arguments instanceof Array); // false
  console.log(a,args); // 1 [2, 3, 4, 5, 6]
}
fn(1,2,3,4,5,6);
let [a,...b] = ['周星驰','吴孟达','王宝强'];
console.log(b); // ['吴孟达','王宝强']
function fn(a,...args) {
  console.log(typeof  args, args instanceof Array) // object true
  console.log(arguments instanceof Array); // false
  console.log(a,args); // 1 [2, 3, 4, 5, 6]
}
fn(1,2,3,4,5,6);

对象结构解析赋值

  • 对象解析赋值
ts
let { userName, b } = {userName: 'wgh', age:18 };
console.log(userName,b); // wgh undefined
let { userName, b } = {userName: 'wgh', age:18 };
console.log(userName,b); // wgh undefined

TIP

左侧是变量名,需要保证和对象中的键要一样的,不然则解析不成功,解析不成功值为undefined

  • 可以给变量名起别名
ts
let { userName: name, userAge: age } = {userName: 'wgh', userAge:18 };
console.log(name, age); // wgh 18
let { userName: name, userAge: age } = {userName: 'wgh', userAge:18 };
console.log(name, age); // wgh 18

TIP

如果起了别名,只能使用别名

  • 如果解构不成功,可以指定默认值
ts
// let { name,age } = obj;
// console.log(name);
// console.log(age);  // undefined

let { name, age=18 } = obj;
console.log(name);
console.log(age);  // undefined
// let { name,age } = obj;
// console.log(name);
// console.log(age);  // undefined

let { name, age=18 } = obj;
console.log(name);
console.log(age);  // undefined

字符串解析赋值

ts
// 字符串的解构赋值
let [a,b,c,d] = "wugh";
console.log(a,b,c,d); // w u g h

let {'0': e,length} = 'wgh';
console.log(a,length) // w 3
// 字符串的解构赋值
let [a,b,c,d] = "wugh";
console.log(a,b,c,d); // w u g h

let {'0': e,length} = 'wgh';
console.log(a,length) // w 3

函数解析赋值

  • 函数的形参列表也可以解构赋值
ts
function foo([x,y]){
    return x+y;
}
console.log(foo([666,888]));
function foo([x,y]){
    return x+y;
}
console.log(foo([666,888]));
  • 如果解构失败,指定默认值
ts
function foo({
    x = 0,
    y = 0
}) {
    return x + y;
}
console.log(foo({
    x:123,
    y:456
}));
function foo({
    x = 0,
    y = 0
}) {
    return x + y;
}
console.log(foo({
    x:123,
    y:456
}));

箭头函数

箭头函数定义

ts
let f = (x, y) => {
  return x + y;
}
console.log(f(1, 2));

// 如果只有一个形参,()可以不写
let f1 = x => {
  return x/3;
}
console.log(f(9));

// 如果函数体只有一条语句,{}和return都可以不写
let f2 = x =>  x / 3;
console.log(f(9));
let f = (x, y) => {
  return x + y;
}
console.log(f(1, 2));

// 如果只有一个形参,()可以不写
let f1 = x => {
  return x/3;
}
console.log(f(9));

// 如果函数体只有一条语句,{}和return都可以不写
let f2 = x =>  x / 3;
console.log(f(9));

箭头函数使用细节

ts
// 函数返回对象
let f = () => {
    return { name:"wc" }
};
// 如果返回的是对象,对象需要使用()包起来
// 如果不包,对象的{}会当成函数的{}
let f1 = () => ({ name: "wc" })
console.log(f());
// 函数返回对象
let f = () => {
    return { name:"wc" }
};
// 如果返回的是对象,对象需要使用()包起来
// 如果不包,对象的{}会当成函数的{}
let f1 = () => ({ name: "wc" })
console.log(f());

箭头函数与函数的区别

  • 写法不同,箭头函数使用箭头定义,写法简洁。 普通函数使用function定义。
  • 箭头函数都是匿名函数,而普通函数既可以是匿名函数,也可以是具名函数。
  • 箭头函数不能作为构造函数来使用,普通函数可以用作构造函数,以此来创建一个对象的实例。
  • this指向不同,箭头函数没有this,在声明的时候,捕获上下文的this供自己使用,一旦确定不会再变化。在普通函数中,this指向调用自己的对象,如果用在构造函数,this指向创建的对象实例。普通函数可以使用call,apply,bind改变this的指向。
  • 箭头函数没有arguments(实参列表,类数组对象),每一个普通函数在调用后都有一个arguments对象,用来存储实际传递的参数。
  • 箭头函数没有原型,而普通函数有。

箭头函数不合适的场景

  • 不能作为类(构造器),不能new
  • 没有prototype显示原型
  • 如果给原型对象上添加方法,方法最好不要写成箭头函数
ts
function Cat(name) {
  this.name = name;
}

function Dog(name) {
  this.name = name;
}

Cat.prototype.sayHello = function(){
  console.log(this.name);
}

Dog.prototype.sayHello = () => {
  console.log(this.name);
}

let cat = new Cat("小咪");
let dog = new Dog("旺财");

cat.sayHello();// 小咪
dog.sayHello();// und
function Cat(name) {
  this.name = name;
}

function Dog(name) {
  this.name = name;
}

Cat.prototype.sayHello = function(){
  console.log(this.name);
}

Dog.prototype.sayHello = () => {
  console.log(this.name);
}

let cat = new Cat("小咪");
let dog = new Dog("旺财");

cat.sayHello();// 小咪
dog.sayHello();// und

思考

ts
var name = "二哈"
let p = {
    name: "旺财",
    getName: function () {
        console.log(this.name);
        return () => {
            console.log(this.name);
        }
    }
}
p.getName()(); // 旺财 旺财
var name = "二哈"
let p = {
    name: "旺财",
    getName: function () {
        console.log(this.name);
        return () => {
            console.log(this.name);
        }
    }
}
p.getName()(); // 旺财 旺财

对象扩展

属性和方法的简写

ts
let uName = "wc";
let uAge = 18;
let person = {
	uName,
	uAge,
	sayHello() {
		console.log("sayHello...");
	}
}
console.log(person.uName);
console.log(person.uAge);
person.sayHello();
let uName = "wc";
let uAge = 18;
let person = {
	uName,
	uAge,
	sayHello() {
		console.log("sayHello...");
	}
}
console.log(person.uName);
console.log(person.uAge);
person.sayHello();

Object.assign

  • 同名属性,后面的覆盖前面的。
ts
const dog1 = { name:"旺财", age: 2 };
const dog2 = Object.assign(dog1, { name: '二哈' });
console.log(dog2); // { name:"二哈", age: 2 }
const dog1 = { name:"旺财", age: 2 };
const dog2 = Object.assign(dog1, { name: '二哈' });
console.log(dog2); // { name:"二哈", age: 2 }
  • 使用api给对象添加属性
ts
const dog1 = { age: 2 };
Object.defineProperty(dog1, 'name', {
  value: '二哈',
  enumerable: false, // 是否可枚举
  configurable: false // 是否可(配置)删除
})
const dog1 = { age: 2 };
Object.defineProperty(dog1, 'name', {
  value: '二哈',
  enumerable: false, // 是否可枚举
  configurable: false // 是否可(配置)删除
})
  • Object.assign 只能copy可枚举的属性
ts
const dog1 = { age: 2 };
Object.defineProperty(dog1, 'name', {
  value: '二哈',
  enumerable: false, // 是否可枚举
  configurable: false, // 是否可(配置)删除
})
Object.assign({},dog1); // { age: 2 }
const dog1 = { age: 2 };
Object.defineProperty(dog1, 'name', {
  value: '二哈',
  enumerable: false, // 是否可枚举
  configurable: false, // 是否可(配置)删除
})
Object.assign({},dog1); // { age: 2 }

封装一个可以实现深copy的方法

ts
function deepClone(source) {
	let newObj = {};
	for(let key in source){
		if(typeof source[key] == "object"){
			newObj[key] = deepClone(source[key])
		}else{
			newObj[key] = source[key]
		}
	}
	return newObj;
}
let obj1 = { name: "wc", address: { city: "bj" } }
let obj2 = deepClone(obj1);
obj1.address.city = "sh";
console.log(obj2.address.city); // bj
function deepClone(source) {
	let newObj = {};
	for(let key in source){
		if(typeof source[key] == "object"){
			newObj[key] = deepClone(source[key])
		}else{
			newObj[key] = source[key]
		}
	}
	return newObj;
}
let obj1 = { name: "wc", address: { city: "bj" } }
let obj2 = deepClone(obj1);
obj1.address.city = "sh";
console.log(obj2.address.city); // bj

Symbol

Proxy

ts
let obj = {
	name: "wc",
	age: 18
}
let objProxy = new Proxy(obj, {
	// 访问属性时,走get,获取值时的捕获器
	get(target, key) {
		console.log(`监听到了obj对象的${key}属性被访问了`);
		return target[key]
	},
	// 设置值时的捕获器
	set(target, key, newValue) {
		console.log(`监听到了obj对象的${key}属性被设置了`);
		target[key] = newValue;
	},
	// 监听delete的捕获器
	deleteProperty(target, key) {
		console.log(`监听到了obj对象的${key}属性被删除了`);
	},
	// 监听in的捕获器
	has(target, key) {
		console.log(`监听到了obj对象的${key}属性in操作`);
		return key in target;
	},
	// 还有其它的捕获器
});
objProxy.name; // 监听到了obj对象的name属性被访问了
let obj = {
	name: "wc",
	age: 18
}
let objProxy = new Proxy(obj, {
	// 访问属性时,走get,获取值时的捕获器
	get(target, key) {
		console.log(`监听到了obj对象的${key}属性被访问了`);
		return target[key]
	},
	// 设置值时的捕获器
	set(target, key, newValue) {
		console.log(`监听到了obj对象的${key}属性被设置了`);
		target[key] = newValue;
	},
	// 监听delete的捕获器
	deleteProperty(target, key) {
		console.log(`监听到了obj对象的${key}属性被删除了`);
	},
	// 监听in的捕获器
	has(target, key) {
		console.log(`监听到了obj对象的${key}属性in操作`);
		return key in target;
	},
	// 还有其它的捕获器
});
objProxy.name; // 监听到了obj对象的name属性被访问了

Set

  • Set创建及基本操作
ts
 const set = new Set();
 set.add(1);
 set.size; // 1
 set.has(1); // true
 set.clear();
 // delete entries values keys
 const set = new Set();
 set.add(1);
 set.size; // 1
 set.has(1); // true
 set.clear();
 // delete entries values keys
  • Set会自动去除重复元素
ts
 const set = new Set();
 set.add(1);
 set.add(1);
// Set(1) {1}

// 数组去重
let arr = [1, 1, 2, 2, 3, 3];
console.log(Array.from(new Set(arr)));
 const set = new Set();
 set.add(1);
 set.add(1);
// Set(1) {1}

// 数组去重
let arr = [1, 1, 2, 2, 3, 3];
console.log(Array.from(new Set(arr)));

Map

  • Map基本操作
ts
const map = new Map();
map.set(name,'旺财');
map.get('name');
map.delete(name);
map.clear()
const map = new Map();
map.set(name,'旺财');
map.get('name');
map.delete(name);
map.clear()