文章目录
1、基本
之前,我们这样写对象:
function Circle(raduis){
this.raduis = raduis;
this.draw = function(){
console.log('draw');
}
}
但有了ES6中的class之后,我们可以这样写:
class Circle{
constructor(radius){
this.radius = radius;
this.move = function(){
console.log('move');
}
}
draw(){
console.log('draw');
}
}
const c = new Circle(1);
在构造器中定义的方法会成为实例成员;
在构造器外定义的方法会成为原型构造成员;
再来看看类的实质:函数
ES6中的类强制使用new操作符,否则会报错。
2、置顶(Hoisting)
有两种声明函数的方式:
// 函数声明
function hello(){}
// 函数表达式
const hello = function(){};
他们的区别在于:函数声明是置顶的,或者说它们自动被抬升到代码最上面,因此我们可以在函数声明之前就调用它,而函数表达式不会置顶。
相似地,类也可以通过类声明和类表达式两种方式来定义。
// 类声明
class Circle{
}
// 类表达式
const Square = class{
}
不同于函数,类声明和类表达式都不会置顶。
3、实例方法和静态方法
在下面这个例子中,draw方法就是实例方法,实例方法只能在实例或者对象中生效。
class Circle{
constructor(radius){
this.radius = radius;
this.move = function(){
console.log('move');
}
}
draw(){
console.log('draw');
}
}
const c = new Circle(1);
下面为上面的代码添加一个名为parse的静态方法:
class Circle{
constructor(radius){
this.radius = radius;
this.move = function(){
console.log('move');
}
}
draw(){
console.log('draw');
}
// 静态方法
static parse(str){
}
}
const c = new Circle(1);
Circle.parse('apple');
静态方法可以通过类名.方法名(参数)
直接访问,而不需要创建类的实例(对象)。
4、深入讨论this关键字
const Circle = function(){
this.draw = function(){
console.log(this);
}
};
const c = new Circle();
c.draw();
我们将draw方法的引用赋值给一个常量,并借助这个常量调用方法:
const draw = c.draw;
draw();
结果window对象:
第一种方式,我们通过对象调用方法,对象中的this指向调用的对象本身。
第二章方式,我们叫做函数调用,因为我们以一种独立的方式调用函数,这种调用没有指向任何对象,当用函数调用的方式调用一个方法时,默认情况下,this会指向全局对象(浏览器中是Window,nodejs中是Global)。
回忆一下使用new操作符创建对象的步骤:当我们使用new操作符时,它先创建一个新的对象,然后将构造函数中的this指向这个新建的对象。
在类中,默认以严格模式解析进行,函数调用方式的调用函数会得到this对象为undefined。
class Circle{
draw(){
console.log(this);
}
}
const c = new Circle();
c.draw();
const draw = c.draw;
draw();
5、ES6环境下如何私有化属性
5.1 方法一:使用Symbol
Symbol()是一个函数,能创建一个Symbol,每个Symboll是一个独立的个体,每次调用Symbol函数都会得到一个新的独立单位,
我们可以用Symbol作为属性的名称:
const _radius = Symbol();
class Circle{
constructor(radius){
this[_radius] = radius;
}
}
const c = new Circle(2);
const _radius = Symbol();
const _draw = Symbol();
class Circle{
constructor(radius){
this[_radius] = radius;
}
[_draw](){
console.log('draw');
}
}
const c = new Circle(2);
5.2 使用WeanMap(弱映射)实现对象成员的私有化
const _radius = new WeakMap(); // 弱映射实际上就是字典,字典里面的键是对象,而值可以随意
const _move = new WeakMap(); // 之所以被叫做“弱映射”,是它的键很弱,一旦没有引用就会被垃圾回收机制回收。
class Circle{
constructor(radius){
_radius.set(this,radius);
_move.set(this,() => {
console.log('move',this);
})
}
draw(){
// 获取弱映射的值
console.log( _radius.get(this));
_move.get(this)();
console.log('draw');
}
}
const c = new Circle(2);
6、get和set方法
const _radius = new WeakMap(); // 弱映射实际上就是字典,字典里面的键是对象,而值可以随意
// 之所以被叫做“弱映射”,是它的键很弱,一旦没有引用就会被垃圾回收机制回收。
class Circle{
constructor(radius){
_radius.set(this,radius);
}
// 可以向属性一样访问
get radius(){
return _radius.get(this);
}
set radius(value){
if(value<=0){
throw new Error("invalid radius");
}
_radius.set(this,value);
}
}
const c = new Circle(2);
7、继承
class Shape{
move(){
console.log('move');
}
}
class Circle extends Shape{
draw(){
console.log("draw");
}
}
const c = new Circle();
class Shape{
constructor(color){
this.color = color;
}
move(){
console.log('move');
}
}
class Circle extends Shape{
constructor(color,radius){
// 子类如果需要构造器,必须先实现父类的构造器
super(color);
this.radius = radius;
}
draw(){
console.log("draw");
}
}
const c = new Circle('red',1);
8、方法重写
class Shape{
constructor(color){
this.color = color;
}
move(){
console.log('move');
}
}
class Circle extends Shape{
constructor(color,radius){
// 子类如果需要构造器,必须先实现父类的构造器
super(color);
this.radius = radius;
}
move(){
console.log("move circle");
super.move();
}
}
const c = new Circle('red',1);
9、练习:实现栈类
const _items = new WeakMap();
class Stack{
constructor(){
_items.set(this,[]);
}
get count(){
return _items.get(this).length;
}
peek(){
}
push(obj){
_items.get(this).push(obj);
}
pop(){
if(_items.get(this).length===0){
throw new Error('Stack is empty');
}
return _items.get(this).pop();
}
peek(){
const items = _items.get(this);
if(_items.get(this).length===0){
throw new Error('Stack is empty');
}
return _items.get(this)[_items.get(this).length-1];
}
}