JavaScript数据结构与算法(一):Stack

说在前面

  • ES5和ES6如何实现类
  • ES5和ES6如何实现私有属性
  • 性能

代码

  • ES5版本:
function Stack() {
  let items = [];
  //添加元素入栈
  this.push = function (ele) {
    items.push(ele);
    };
  // 弹出栈顶元素
  this.pop = function () {
    return items.pop();
    };
  // 查看栈顶元素
  this.peek = function () {
    return items[items.length-1];
    };
  // 判断栈顶是否为空
  this.isEmpty = function () {
    return items.length == 0;
    };
  // 返回元素个数
  this.size = function () {
    return items.length;
    };
  // 清除栈
  this.clear = function () {
    items = [];
    };
  // 打印栈内元素
  this.print = function () {
    console.log(items.toString());
    };
}
  • ES6版本

    ES6的类是基于原型的,比基于函数的类更节省内存。

class Stack {
  constructor() {
    this.items = [];
  }
  push(ele) {
    this.items.push(ele);
  }
  pop() {
    return this.items.pop();
  }
  peek() {
    return this.items[this.items.length-1];
  }
  isEmpty() {
    return this.items.length == 0;
  }
  size() {
    return this.items.length;
  }
  clear() {
    this.items = [];
  }
  print() {
    console.log(this.items.toString());
  }
}

测试代码

let stack = new Stack();
console.log(stack.isEmpty());
stack.push(1);
stack.push(2);
stack.push(3);
stack.print();

console.log("stack peek",stack.peek());
console.log("stack size",stack.size());
console.log("return pop",stack.pop());
console.log("after pop",stack.size());
stack.clear();
console.log("after clear",stack.size());

输出:

F:\js>node test.js
true
1,2,3
stack peek 3
stack size 3
return pop 3
after pop 2
after clear 0

改进

不管是ES5还是ES6,items总是暴露给外界的,是公共的,这不符合面向对象的要求。利用ES6中的Symbol基本类型,因为它是不可变的,可以用作对象的属性,从有创建“假的私有属性”。只需要把this.items改成this[_items]

let _items = Symbol();

class Stack {
  constructor() {
    this[_items] = [];
  }
  push(ele) {
    this[_items].push(ele);
  }
  pop() {
    return this[_items].pop();
  }
  peek() {
    return this[_items][this[_items].length-1];
  }
  isEmpty() {
    return this[_items].length == 0;
  }
  size() {
    return this[_items].length;
  }
  clear() {
    this[_items] = [];
  }
  print() {
    console.log(this[_items].toString());
  }
}

然而,还是可以通过一些方法破坏这种私有封装,ES6新增的Object.getOwnPropertySymbols();方法不是吃素的。

console.log("stack peek",stack.peek());
console.log("stack size",stack.size());
console.log("return pop",stack.pop());
console.log("after pop",stack.size());
stack.clear();
console.log("after clear",stack.size()); //0

//获取symbol属性
let objectsSymbols = Object.getOwnPropertySymbols(stack);
console.log(objectsSymbols[0]);
stack[objectsSymbols[0]].push(4);
stack.print();//4

那,我们是不是就没有其他办法来实现真正的私有属性呢?答案显然是肯定的!ES6提供有一种数据类型是可以实现私有的,那就是WeakMap


// 使用闭包函数将stack类包起来,items只能在函数内访问,从而保证私有。
Stack = (function () {
  const items = new WeakMap();
  class Stack {
    constructor() {
      items.set(this,[]);
    }
    push(ele) {
      let s = items.get(this);
      s.push(ele);
    }
    pop() {
      return items.get(this).pop();
    }
    peek() {
      return items.get(this)[items.get(this).length-1];
    }
    isEmpty() {
      return items.get(this).length == 0;
    }
    size() {
      return items.get(this).length;
    }
    clear() {
      items.set(this,[]);
    }
    print() {
      console.log(items.get(this).toString());
    }
  }
  return Stack;
  })();

// 使用栈

let stack = new Stack();
console.log(stack.isEmpty());
stack.push(1);
stack.push(2);
stack.push(3);
stack.print();

console.log("stack peek",stack.peek());
console.log("stack size",stack.size());
console.log("return pop",stack.pop());
console.log("after pop",stack.size());
stack.clear();
console.log("after clear",stack.size());

测试

F:\js>node test.js
true
1,2,3
stack peek 3
stack size 3
return pop 3
after pop 2
after clear 0

小结

虽然ES6引入了类的语法,但是JS这门语言还是没有像其他语言那样可以生命私有属性的语法,但是可以通过JS的一些特性帮助完成这一个过程,例如函数闭包。使用ES6的语法实现类,使得编程更加简洁美观,从性能上比使用函数实现的类要好,因为其内存开销更少。

猜你喜欢

转载自blog.csdn.net/w_bu_neng_ku/article/details/80341529