let 和 const
1、使用let声明变量
在JS中,JS代码是交给JS解析线程来处理的,在开始执行前会有一个预编译的过程。var声明的变量会提升。例如:
console.log(a); // undefined
var a = 110;
console.log(a); // 110
复制代码
用var声明的变量除了在函数中是局部变量外,其余都是全局变量,并且可以重复声明。
ES6在之前的基础上,新增了let命令来声明变量。它的用法类似于var,但是声明的变量只在块级作用域内有效,即{}。 并且为了纠正var命令会发生的“变量提升”现象,改变了语法行为,它所声明的变量一定要在声明后使用,否则报错。
{
console.log(a); // not defined
let a = 110;
console.log(a); // 110
}
console.log(a); // not defined
复制代码
除此,let还不允许在相同作用域内,重复声明一个变量。可以说是大大的优化了var的语法漏洞。
补充:因为let的块级作用域,十分适合做for循环的计数器。例如:
for(let i=0;i<10;i++){
console.log(i);
}
复制代码
上面的代码如果使用var,最后输出的是10。 然而let有着块级作用域,当前的i只在本轮循环中有效,所以每一次循环的i其实都是一个新的变量,所以最后输出的是0~10。
2、使用const声明常量
const声明一个只读的常量。一旦声明,常量的值就不能改变。
const a = 11;
a = 22; // 再次赋值就会报错
复制代码
const声明的变量不得改变值,这意味着,const一旦声明变量,就必须立即初始化,不能留到以后赋值。
const与let命令有很多相同之处:用const声明的变量也是不提升的,不可重复声明,且只在声明所在的块级作用域内有效。
还有,如果const声明的是一个对象,对象里面所包含的值是可以被修改的。抽象一点儿说,就是对象所指向的内存地址不能改变,而变量成员是可以修改的。
const a = {name:"wangcai"};
a.name = "xiaoqiang"; // 没问题
a = {name:"xiaoqiang"}; // 报错
复制代码
const实际上保证的,并不是变量的值不得改动,而是变量指向的那个内存地址所保存的数据不得改动。对于基本数据类型,值就保存在变量指向的那个内存地址,因此等同于常量。但对于引用数据类型,变量指向的内存地址,保存的只是一个指向实际数据的指针,const只能保证这个指针是固定的,至于它指向的数据结构是不是可变的,就完全不能控制了。因此,将一个对象声明为常量必须非常小心。
函数
1、箭头函数
目前我们所知道的创建函数有两种方式:
function f(){} // 函数声明
var f = function(){} // 函数表达式
复制代码
在ES6中,又为我们增加了一个创建函数的快捷写法——箭头函数,不需要function关键字。
var f = () => {}
复制代码
注意细节:
-
当函数有且仅有一个参数时,可以省略掉小括号。
-
当函数返回有且仅有一个表达式时,可以省略{}和return;
// 例如: var f = x => x*x; // 等价于: var f = function(x){ return x*x; } 复制代码
2、函数默认参数
在ES6中,JS的形参可以有默认值,以便在没有实参被传递进去时使用。
function f(x,y=100){
return x+y;
}
console.log(f(1));
复制代码
通常情况下,定义了默认值的参数,应该是函数的尾参数。因为这样比较容易看出来到底省略了哪些参数。如果非尾部的参数设置默认值,实际上这个参数是没法省略的。参数变量是默认声明的,所以不能用let或const再次声明。否则会报错。
3、函数的length属性
指定了默认值以后,函数的length属性,将返回没有指定默认值的参数个数。
(function(a){}).length; // 1
(function(a=5){}).length; // 0
(function(a,b,c=5){}).length; // 2
复制代码
这是因为length属性的含义是,该函数预期传入的参数个数。某个参数指定默认值以后,预期传入的参数个数就不包括这个参数了。
但是,如果设置了默认值的参数不是尾参数,那么length属性也不再计入后面的参数了。
(function(a=5,b,c){}).length; // 0
(function(a,b=5,c){}).length; // 1
(function(a,b,c=5){}).length; // 2
复制代码
字符串扩展
1、模板字符串
传统的JavaScript语言,输出模板通常是这样写的:
var name = "hello";
var age = 18;
console.log("我叫"+name+",今年"+age+"岁了");
复制代码
上面这种写法相当繁琐,所以在ES6中,引入了模板字符串``解决这个问题。
var name = "hello";
var age = 18;
console.log(`我叫${name},今年${age}岁了`);
复制代码
2、trim()
trim方法用于去除字符串空格。
- trim():去掉左右空格;
- trimLeft():去掉左空格;
- trimRight():去掉右空格。
var str = " a b ab ";
console.log(str.trim()); // "a b ab"
console.log(str.trimLeft()); // "a b ab "
console.log(str.trimRight()); // " a b ab"
复制代码
3、includes(), startsWith(), endsWith()
传统上,JS中只有indexOf方法,可以用来确定一个字符串是否包含在另一个字符串中。除此之外,ES6又提供了三种新方法:
- includes():表示是否找到了参数字符串。
- startsWith():表示参数字符串是否在原字符串的头部。
- endsWith():表示参数字符串是否在原字符串的尾部。
var str = "abc def";
console.log(s.startsWith("abc")); // true
console.log(s.endsWith(" def")); // true
console.log(s.includes("cd")); // false
复制代码
4、repeat()
repeat方法返回一个新字符串,表示将原字符串重复n次。
"123".repeat(3); // 123123123
"123".repeat(2.9); // 123123
"123".repeat(-1); // 报错
"123".repeat(0); // ""
"123".repeat("3"); // 123123123
复制代码
- 参数如果是小数,会被取整。
- 如果参数是负数,会报错。
- 如果没有参数或参数为0,则结果为""。
- 如果参数是字符串,则会先转换成数字。
5、padStart(),padEnd()
ES7中引入了字符串补全长度的功能。如果某个字符串不够指定长度,会在头部或尾部补全。padStart()用于头部补全,padEnd()用于尾部补全。
padStart和padEnd中有两个参数,第一个参数用来指定字符串的长度,第二个参数是用来补全的字符串。
abc.padStart(5,"*"); // "**abc"
abc.padEnd(5,"*"); // "abc**"
复制代码
如果用来补全的字符串与原字符串,两者的长度之和超过了指定的长度,则会截去超出位数的补全字符串。
abc.padStart(5,"123"); // "12abc"
abc.padEnd(5,"123"); // "abc12"
复制代码
如果原字符串的长度,等于或大于指定的长度,则返回原字符串。
abc.padStart(2,"123"); // "abc"
abc.padEnd(2,"123"); // "abc"
复制代码
如果省略第二个参数,默认使用空格补全长度。
abc.padStart(10); // " abc"
abc.padEnd(10); // "abc "
复制代码
数组扩展
在ES6中,Array对象增加了一些新的静态方法,Array原型上也增加了一些新方法。
1、Array.from()
Array.from()是Array构造器的静态方法。作用是:将伪数组对象和可遍历的对象转化成真正的数组。
伪数组对象包括:函数中的arguments、由document.getElementsByTagName()返回的数组对象、新增加的Map和Set数据结构。
let lis = document.getElementsByTagName("li");
console.log(Array.isArray(lis)); // false
console.log(Array.isArray(Array.from(lis))); // true
复制代码
如果参数是一个真正的数组,Array.from会返回一个一模一样的新数组。
console.log(Array.from([1,2,3])); // [1,2,3]
复制代码
2、Array.of()
Array.of()方法用于将一组值转换为数组。可以理解为用来创建数组。
主要目的是弥补构造器Array()的不足:因为参数个数的不同,会导致Array()的行为有差异。
console.log(Array()); // []
console.log(Array(3)); // [<3 empty items>]
console.log(Array("3")); // ['3']
console.log(Array(1,2,3)); // [1,2,3]
console.log(Array.of()); // []
console.log(Array.of(3)); // [3]
console.log(Array.of("3")); // ['3']
console.log(Array.of(1,2,3)); // [1,2,3]
复制代码
Array.of基本上可以用来替代Array()或new Array(),并且不存在由于参数不同而导致的重载。它的行为非常统一。
Array.of总是返回参数值组成的数组。如果没有参数,就返回一个空数组。
3、find() 和 findIndex()
find:用于找出第一个符合条件的数组元素。找不到则是undefined。注意,它是不会返回多个,只找一个,找到了就返回。如果你要把所有的满足条件的数组元素素都找出来,你应该用filter()
findIndex:返回第一个符合条件的数组元素的索引。找不到则是-1;
let arr = [
{name:"zs1",score:85},
{name:"zs2",score:91},
{name:"zs3",score:88},
{name:"zs4",score:74},
{name:"zs5",score:59},
]
let rs = arr.find(item=>item.score>85)
console.log(rs); // { name: 'zs2', score: 91 }
let f = arr.findIndex(item=>item.score>85)
console.log(f); // 1
复制代码
4、includes()
includes方法返回一个布尔值,表示某个数组是否包含给定的值,与字符串的includes方法类似。
let arr = [1,2,3]
console.log(arr.includes(1)); // true
console.log(arr.includes("a")); // false
复制代码
没有该方法之前,我们通常使用数组的indexOf方法,indexOf()也可以做类似的工作。返回值是:0或-1
let arr = [1,2,3]
console.log(arr.indexOf(1)); // 0
console.log(arr.indexOf("a")); // -1
复制代码
但是,因为indexOf它内部使用严格相等运算符(===)进行判断,对NaN的判断是错误的,而includes没有这个问题。
console.log([NaN,1,2,3].indexOf(NaN)); // -1
console.log([NaN,1,2,3].includes(NaN)); // true
复制代码
5、fill()
作用:给数组填充指定值。fill方法用于空数组的初始化非常方便。但是已有数据会被覆盖。
let arr = new Array(5);
console.log(arr.fill("*")); // ['*','*','*','*','*']
console.log([1,2,3].fill("*")); // ['*','*','*']
复制代码
fill方法还可以接受第二个和第三个参数,用于指定填充的起始位置和结束位置(表示下标,包括起点,不包括终点)。
let arr = new Array(5);
console.log(arr.fill("*",0,2)); // ['*','*',<3 empty items>]
console.log([1,2,3].fill("*",1,2)); // [1,'*',3]
复制代码
6、数组的扩展运算符
扩展运算符是三个点(...),用于在特定地方扩展元素,写法简便快捷,用法也十分给力。
(1)复制数组
let arr = [1,2,3];
let arr1 = [...arr]
console.log(arr1); // [1,2,3]
arr1[0] = 66;
console.log(arr); // [1,2,3]
console.log(arr1); // [66,2,3]
复制代码
上面代码中,用...很简单的复制了一个新数组,且若修改arr1中的值不会对arr产生任何影响产生影响。
(2)合并数组
扩展运算符不仅可以合并数组,还可以在一个数组中扩展另一个数组的元素。
let arr = [1,2,3];
let arr1 = [4,5,6]
let arr2 = [...arr,...arr1,7,8,9]
console.log(arr2); // [ 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
复制代码
(3)字符串转成数组
let str = "hello";
let arr = [...str]
console.log(arr); // [ 'h', 'e', 'l', 'l', 'o' ]
复制代码
(4)伪数组转成数组
let lis = document.getElementsByTagName("li");
console.log(Array.isArray(lis)); // false
console.log(Array.isArray([...lis])); // true
复制代码
目前把一个伪数组转成数组有如下几种方式:
- Array.prototype.slice.call();
- Array.from();
- [...伪数组对象]
7、数组的解构赋值
ES6允许按照一定模式,从数组中提取值,对变量进行赋值,这被称为解构(Destructuring)。
以前,为变量赋值,只能直接指定值。
let arr = [1,2,3]
let a = arr[0];
let b = arr[1];
let c = arr[2];
复制代码
ES6可以用解构模式,从数组中提取值,按照对应位置,直接对变量进行赋值。
let [a, b, c] = [1, 2, 3];
复制代码
本质上,这种写法属于“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
注意细节:
(1)左右结构不一样
let [a,b,c,d] = [1,2,3]
console.log(a);
console.log(b);
console.log(c);
console.log(d); // undefined
复制代码
(2)跳过部分
let [a,,c] = [1,2,3]
console.log(a); // 1
console.log(c); // 3
复制代码
(3)默认值
let [a=11,b=22,c,d=666] = [0]
console.log(a); // 0
console.log(b); // 22
console.log(c); // undefined
console.log(d); // 666
复制代码
(4)嵌套
let [a,b,c,[d]] = [1,2,[3],[4]]
console.log(a); // 1
console.log(b); // 2
console.log(c); // [3]
console.log(d); // 4
复制代码
对象扩展
1、对象的简写
(1)属性的简写
属性名是可以简写的,但是有前提条件:属性的值是一个变量;变量名称和键名是一致的。
var name = "wangcai";
var age = 20;
var obj = {
//name:name,age:age
name,age
};
复制代码
(2)方法的简写
除了属性,方法也可以简写,可以省略掉:和function。
var obj = {
// hello:function(){console.log("hello...")}
hello(){console.log("hello...")}
};
复制代码
2、属性名表达式
JS定义对象的属性,有两种方法。除了我们最常用的.语法,还有一个[]语法,使用如下:
- 对象名.[“属性名”]
- 对象名.[变量]
- 对象名.[常量]
- 对象名.[表达式]
var obj = {
name:"wangcai",
3:false,
};
var m = "name";
console.log(obj["name"]);
console.log(obj[m]); // wangcai
console.log(obj.m); // undefined
console.log(obj[3]);
console.log(obj["n"+"a"+"m"+"e"]);
复制代码
如果属性是一个变量,那么只能通过[]语法。所以说[]语法更加灵活,能力比.语法更强大。
3、Object.assign()
Object.assign方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)。
var obj1 = {a:0};
var obj2 = {a:1};
var obj3 = {a:11,b:22};
console.log(Object.assign(obj1,obj2,obj3)) // { a: 11, b: 22 }
复制代码
Object.assign也可以用来处理数组,但是会把数组视为对象。
Object.assign([1, 2, 3], [4, 5]); // [4, 5, 3]
复制代码
注意细节:
- 第一个参数是目标对象,assign这个方法把其它的参数中的属性全部加在第一个参数身上;
- 第一个参数在属性复制过程中会被修改,后面的会覆盖前面的属性;
- assign这个方法的返回值就是第一个参数的引用,也就是返回了第一个参数;
- assign这个方法会把原型上面的属性也拷贝过来;
- assign不能拷贝继承过来的属性;
- assign也不能拷贝不可枚举的属性;
- assign是浅拷贝(仅拷贝内存地址)。
4、对象扩展运算符
对象中的扩展运算符类似于数组中的扩展运算符,作用是取出参数对象的所有可遍历属性,拷贝到当前对象中。一般用于复制对象,合并对象等。
不同的是,对象是{},数组是[],在打印输出时若...被()包起来,[]可以省略不写。
let obj = {a:1,b:2};
let arr = [1,2,3];
console.log({...obj}); // { a: 1, b: 2 }
console.log(...arr); // 1 2 3
let obj1 = {
a:1,b:2,c:3
};
let obj2 = {
d:4,e:5
}
let rs = {...obj1,...obj2}
console.log(rs); // { a: 1, b: 2, c: 3, d: 4, e: 5 }
复制代码
5、属性相关的方法
(1)Object.getOwnProertyDescriptor()
获取一个对象中某个属性的详细信息。
var a = 110;
console.log(Object.getOwnPropertyDescriptor(window,"a"));
复制代码
(2)Object.defineProperty()
精细化设置一个对象的属性。属性的四个特征:
- configurable:是否可以删除。默认为true,可以删除;
- writable:是否可以修改。默认为ture, 可以修改;
- enumerable:是否可以枚举。默认为ture, 可以枚举;
- value:值。默认值为undefined。
格式:Object.defineProperty(对象名,“属性名”,{上面的四个特征});
var obj = {};
Object.defineProperty(obj,"name",{
configurable:false,
writable:false,
enumerable:false,
value:"wangcai"
})
复制代码
(3)Object.defineProperties()
精细化设置多个对象的属性。
var obj = {};
Object.defineProperty(obj,{
"name":{
configurable:false,
writable:false,
enumerable:false,
value:"wangcai"
},
"age":{
configurable:false,
writable:false,
enumerable:false,
value:"66"
}
})
console.log(obj.name,obj.age); // wangcai 66
复制代码
(4)Object.getOwnPropertyNames()
获取自身的属性,以数组的格式返回的。
var obj = {
name:"wangcai",
age:20
}
console.log(Object.getOwnPropertyNames(obj)); // ['name', 'age']
复制代码
(5)Object.keys()
用来获取对象自身可枚举的属性键,以数组的形式返回。
var obj = {
name: "wangcai",
age: 66
};
Object.defineProperty(obj, "name", {
enumerable: false,
});
console.log(Object.keys(obj)); // ['age']
复制代码
目前对于对象的遍历有三种方式:
- for in:会输出自身以及原型链上可枚举的属性;
- Object.getOwnPropertyNames():用来获取对象自身的全部属性名;
- Object.keys():用来获取对象自身可枚举的属性键。
(6)Object.values()
用来获取对象自身可枚举的属性值,以数组的形式返回。
var obj = {
name: "wangcai",
age: 66
};
Object.defineProperty(obj, "name", {
enumerable: false,
});
console.log(Object.values(obj)); // [66]
复制代码
6、继承相关的方法
(1)Object.create()
使用Object.create比较适合对字面量对象的继承。
function NBA(name,age,height){
this.name = name;
this.age = age;
this.height = height;
}
NBA.prototype.say = function(){
console.log(`我是${this.name},今年${this.age},身高是${this.height}cm`);
}
var n1 = new NBA("库里",30,191);
var n2 = Object.create(n1);
复制代码
(2)Object.setPrototypeOf() 和 Object.getPrototypeOf()
Object.setPrototypeOf方法的作用与__proto__相同,用来设置一个对象的prototype对象,返回参数对象本身。
// 格式
Object.setPrototypeOf(object, prototype)
复制代码
Object.setPrototypeOf与Object.setPrototypeOf方法配套,用于获取创建这个对象的那个构造器的prototype属性。
var obj = {
name: "wangcai",
age: 66
};
console.log(Object.getPrototypeOf(obj) == Object.prototype); // true
console.log(Object.getPrototypeOf([]) == Array.prototype); // true
复制代码
7、防篡改方法
可以对对象进行保护,分为三个级别:
-
Object.preventExtensions():不允许新增,但是可以修改,也可以删除;
var obj = { name: "wangcai", age: 66 }; Object.preventExtensions(obj); obj.sex = "man"; console.log(obj); // Object {name: "wangcai", age: 66} 复制代码
-
Object.seal():不允许新增,也不允许删除,但是可以修改;
var obj = { name: "wangcai", age: 66 }; Object.seal(obj); delete obj.age; console.log(obj); // Object {name: "wangcai", age: 66} 复制代码
-
Object.freeze():不允许新增,也不允许删除和修改。
var obj = { name: "wangcai", age: 66 }; Object.freeze(obj); obj.age = 88; console.log(obj); // Object {name: "wangcai", age: 66} 复制代码
也可以使用isExtensible, isSealed, isFrozen来判断当处处理如个保护状态
var obj = {
name: "wangcai",
age: 66
};
// Object.isExtensible()表示是否可扩展
console.log(Object.isExtensible(obj)); // true
Object.freeze(obj);
console.log(Object.isExtensible(obj)); // false
console.log(Object.isSealed(obj)); // true
console.log(Object.isFrozen(obj)); // true
复制代码
严格模式
之前学习的JS,语法非常灵活,JS中这个灵活的特性,弊大于先利。后来增加了严格模式。使用严格模式的目的:规范化、提高编译效率。启动严格模式:"use strict"。
严格模式和非严格模式有什么区别:
- 在严格模式下,不能使用没有var的变量
- 在严格模式下,不能使用8进制的数字
- 在严格模式下,不能把函数定义在if语句中
- 在严格模式下,函数不能有重名的形参
- 在严格模式下,function中的this就不再是window了
- 在严格模式下,arguments不再跟踪形参的变化,即不再与形参一一对应了
- 还可以在函数中启动严格模式
"use strict"
// a = 100;
// var a = 01;
// if(true){
// function f(a,a){
// console.log("f....");
// }
// }
// f();
function f(a,b){
"use strict"
console.log(this); //undefined
console.log(a,b); //1,2
console.log(arguments[0],arguments[1]); //1,2
arguments[0] = 1111;
arguments[1] = 2222;
console.log(a,b); // 1,2
console.log(arguments[0],arguments[1]); // 1111,2222
}
f(1,2);
复制代码
Set 和 Map 结构
1、Set
Set是一种新的数据结构,它类似于数组,但是成员的值都是唯一的,没有重复的值。
Set本身是一个构造函数,用来生成Set数据结构。生成时会自动去重。
Set的四个操作方法:
- add(value):添加某个值,返回 Set 结构本身。
- delete(value):删除某个值,返回一个布尔值,表示删除是否成功。
- has(value):返回一个布尔值,表示该值是否为Set的成员。
- clear():清除所有成员,没有返回值。
// 里面要放一个数组 []
var s = new Set([1,2,3,1,2,3])
// 可以使用add()添加元素
s.add(4);
s.add(5);
s.add(4);
s.add(5);
s.delete(5); // 删除
console.log(s); // Set(5) {1, 2, 3, 4, 5}
console.log(typeof s); // object
复制代码
Set中可以用forEach和for of遍历,for in不行。
s.forEach(item=>console.log(item));
for(var p of s){
console.log(p);
}
复制代码
Set不是数组,只是一个像对象的伪数组
console.log(Array.isArray(s)); // false
console.log(Array.isArray(Array.from(s))); // true
复制代码
Set的经典应用案例————数组去重:
// 扩展运算符和Set结构相结合,就可以去除数组的重复成员。
var arr = [1,2,3,1,2,3,true,"hello",true]
var arr1 = [...(new Set(arr))]
console.log(arr1); // [1,2,3,true,"hello"]
复制代码
2、Map
JavaScript的对象(Object),本质上是键值对的集合(Hash 结构),但是传统上只能用字符串当作键。这给它的使用带来了很大的限制。
为了解决这个问题,ES6提供了Map数据结构。它类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键。也就是说,Object结构提供了“字符串—值”的对应,Map结构提供了“值—值”的对应,是一种更完善的Hash结构实现。如果你需要“键值对”的数据结构,Map比Object更合适。
-
set(key, value):set方法设置键名key对应的键值为value,然后返回整个Map结构。如果key已经有值,则键值会被更新,否则就新生成该键。
-
get(key):get方法读取key对应的键值,如果找不到key,返回undefined。
var a = true;
var m = new Map([
[a,"hello"],
[1,123],
[false,{name:"wangcai"}],
[[1,2,3],a]
]);
console.log(m); // Map {
// true => 'hello',
// 1 => 123,
// false => { name: 'wangcai' },
// [ 1, 2, 3 ] => true }
// 对于基本数据类型,重复的键会覆盖
m.set(true,"abc");
m.set([1,2,3],1);
console.log(m); // Map {
// true => 'abc',
// 1 => 123,
// false => { name: 'wangcai' },
// [ 1, 2, 3 ] => true,
// [ 1, 2, 3 ] => 1 }
console.log(m.get(1)); // 123
// m.get([1,2,3])获取不到值的原因是:get()要比较栈区中的地址,而不是堆区中的数据
console.log(m.get([1,2,3])); // undefined
复制代码
Class
1、简介
JavaScript语言中,生成实例对象的传统方法是通过构造器。
function Point(x, y) {
this.x = x;
this.y = y;
}
Point.prototype.toString = function () {
return this.x + this.y ;
};
var p = new Point(1, 2);
复制代码
上面这种写法跟传统的面向对象语言(比如 C++ 和 Java )差异很大,ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类。
基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语法而已。上面的代码用ES6的class改写,就是下面这样。
//定义类
class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
toString() {
return this.x + this.y ;
}
}
var point = new Point(2, 3);
复制代码
上面代码定义了一个“类”,可以看到里面有一个constructor方法,这就是构造方法,而this关键字则代表实例对象。也就是说,ES5的构造器Point,对应ES6的Point类的构造方法。
2、严格模式
类和模块的内部,默认就是严格模式,所以不需要使用 "use strict" 指定运行模式。只要你的代码写在类或模块之中,就只有严格模式可用。
考虑到未来所有的代码,其实都是运行在模块之中,所以ES6实际上把整个语言升级到了严格模式。
3、constructor
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。
class Point {
}
// 等同于
class Point {
constructor() {}
}
复制代码
4、Class的静态方法
类相当于实例的原型,所有在类中定义的方法,都会被实例继承。如果在一个方法前,加上static关键字,就表示该方法不会被实例继承,而是直接通过类来调用,这就称为“静态方法”。
class Point {
static say(){ console.log("hello")}
}
Point.say();
复制代码
5、Class的继承
(1)简介
Class 可以通过extends关键字实现继承,这比ES5的通过原型链实现继承,要清晰和方便很多。
class Point {
}
class ColorPoint extends Point {
}
复制代码
(2)Object.getPrototypeOf()
Object.getPrototypeOf方法可以用来从子类上获取父类。因此,可以使用这个方法判断,一个类是否继承了另一个类。
Object.getPrototypeOf(ColorPoint) === Point // true
复制代码
(3)super关键字
super()代表调用父类的构造函数。ES6要求,子类的构造函数必须执行一次super函数。
class A {}
class B extends A {
constructor() {
super();
}
}
复制代码
super虽然代表了父类A的构造函数,但是返回的是子类B的实例,即super内部的this指的是B,因此super()在这里相当于A.prototype.constructor.call(this)。
(4)类的prototype属性和__proto__属性
大多数浏览器的ES5实现之中,每一个对象都有__proto__属性,指向对应的构造函数的prototype属性。Class作为构造函数的语法糖,同时有prototype属性和__proto__属性,因此同时存在两条继承链。
-
子类的__proto__属性,表示构造函数的继承,总是指向父类。
-
子类prototype属性的__proto__属性,表示方法的继承,总是指向父类的prototype属性。
class A {
}
class B extends A {
}
B.__proto__ === A // true
B.prototype.__proto__ === A.prototype // true
复制代码
新手小白,刚刚上路,学习总结,请多关照!