JavaScript

78 阅读2分钟

JavaScript

Object.create()

The Object.create()  static method creates a new object, using an existing object as the prototype of the newly created object.

可以用它来取得父class的prototype来赋值给子class的prototype来实现继承:

function Person(fName, lName) {
  this.firstName = fName;
  this.lastName = lName;
}
Person.prototype.getFullName = function () {
  return this.firstName + ' ' + this.lastName;
}
function Employee(fName, lName, eId) {
  // 调用父class的constructor.
  Person.call(this, fName, lName);
  this.empId = eId;
}
// 这里的prototype就和Person的prototype完全相等。
Employee.prototype = Object.create(Person.prototype);
Employee.prototype.constructor = Employee;

Symbol

将Symbol作为key赋值object需要使用中括号:

const obj = {prop1: 123, [Symble('test2')]: 456}

for...in 来循环一个iterable对象或者Object.keys()JSON.stringify()的时候不会包含里面的Symbol key, 这是为了向前兼容,因为es5的时候并不认识Symbol。

for-in ignores Symbol-keyed properties

const obj = {
    [Symbol("x")]: "foo"
};
for (const name in obj) {
    console.log(`name = ${String(name)}`); // never runs
}

但是依然可以使用Reflect.ownKeys()来获得所有的key,包含string和Sybol:

function tryToAddPrivate(o) {
  o[Symbol('Pseudo Private')] = 42;
}
const obj = { prop: 'hello' };
tryToAddPrivate(obj);
console.log(Reflect.ownKeys(obj)); // [ 'prop', Symbol(Pseudo Private) ]
console.log(obj[Reflect.ownKeys(obj)[1]]); // 42

Symbol.for()

会在全局注册范围内搜索给定的key的Symbol, 如果没找到则生成它:

console.log(Symbol.for('bar') === Symbol.for('bar'));
// Expected output: true

console.log(Symbol('bar') === Symbol('bar'));
// Expected output: false

const symbol1 = Symbol.for('foo');

console.log(symbol1.toString());
// Expected output: "Symbol(foo)"

Symbol.iterator

The Symbol.iterator static data property represents the well-known symbol @@iterator. The iterable protocol looks up this symbol for the method that returns the iterator for an object. In order for an object to be iterable, it must have an @@iterator key.

无论什么样的object,只要实现了[Symbol.iterator]属性就实现了iterable protocol , 可以被for...in循环和进行解构。

const iterable1 = {};

iterable1[Symbol.iterator] = function* () {
  yield 1;
  yield 2;
  yield 3;
};

console.log([...iterable1]);
// Expected output: Array [1, 2, 3]

Symbol的好处

防止object的属性名冲突

const library1property = Symbol('lib1');
function lib1tag(obj) {
  obj[library1property] = 42;
}
const library2property = Symbol('lib2');
function lib2tag(obj) {
  obj[library2property] = 369;
}

虽然用library1property和library2property赋值成random string也能防止冲突,但是Symbol的方案有个好处就是可以隐藏Symbol的key,让循环或者JSON.stringify()时对外不可见,这就保证了如果使用的lib方法中添加了lib中的属性时,这个属性是private的。

其实也可以用如下方法来让string的key来模仿Symbol:

const obj = {};
obj[Symbol()] = 1;
Object.defineProperty(obj, 'foo', {
  enumberable: false,
  value: 2
});
console.log(Object.keys(obj)); // []
console.log(Reflect.ownKeys(obj)); // [ 'foo', Symbol() ]
console.log(JSON.stringify(obj)); // {}

medium.com/intrinsic-b…

比如下方如果user是import自另外一个module的,然后我们想在user上加上自己的属性但是又不想影响module原本的功能:

let user = { // belongs to another code
  name: "John"
};
let id = Symbol("id");
user[id] = 1;
alert( user[id] ); // we can access the data using the symbol as the key