const person = {};
// set
person.name = 'Bob';
// get
const name = person.name;
let name;
const person = {
get name() {
return name;
},
set name(newName) {
name = newName;
},
}
person.name = 'Bob';
console.log(person.name); // Bob
ES5.1
let name;
function getName() {
return name;
}
function setName(newName) {
name = newName;
}
const person = {}
person.__defineGetter__('name', getName);
person.__defineSetter__('name', setName);
person.name = 'Bob';
console.log(person.name); // Bob
ES5 以前
屬性值 取出 跟 存入 的時候叫的 function
function doNothing() {}
const person = {
get name() {
return 'Stanney';
},
set name(newName) {
doNothing();
},
};
person.name = 'Bob';
console.log(person.name); // Stanney
parameters:
(1) targetObject
(2) key (property name)
(3) descriptor
.get
.set
.value
.writable
.enumerable
.configurable
ES5.1
function doNothing() {}
const person = {};
Object.defineProperty(person, 'name', {
get() {
return 'Stanney';
},
set(newName) {
doNothing();
},
});
parameters:
(1) targetObject
(2) key (property name)
(3) descriptor
.get
.set
.value
.writable
.enumerable
.configurable
ES5
const person = { name: 'Bob' };
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {
// value: "Bob",
// writable: true,
// enumerable: true,
// configurable: true
// }
-> 能不能修改屬性值
-> 能不能用 Object.keys(target), for ... in
-> 能不能改屬性的 descriptor
const person = {};
Object.defineProperty(person, 'name', { value: 'Bob' });
console.log(Object.getOwnPropertyDescriptor(person, 'name'));
// {
// value: "Bob",
// writable: false,
// enumerable: false,
// configurable: false
// }
getter, setter 無法被綁定到
同時擁有實際數值的屬性
const personA = { get name() { return 'Bob' } };
Object.getOwnPropertyDescriptor(personA, 'name');
// {
// get: ƒ,
// set: undefined,
// enumerable: true,
// configurable: true
// }
const personB = { name: 'Bob' };
Object.getOwnPropertyDescriptor(personB, 'name');
// {
// value: "Bob",
// writable: true,
// enumerable: true,
// configurable: true
// }
const person = {};
const handler = {
get(target, prop) {
if (prop === 'name') return 'Bob';
return target[prop];
},
};
const personYouSee = new Proxy(person, handler);
console.log(personYouSee.name); // Bob
ES6
parameters:
(1) targetObject
(2) handler
handler
.has()
.get()
.set()
.getPrototypeOf()
.setPrototypeOf()
.isExtensible()
.preventExtensions()
.getOwnPropertyDescriptor()
.defineProperty()
.deleteProperty()
.ownKeys()
.apply()
.construct()
the in operator
getting property values
setting property values
Object.getPrototypeOf
Object.setPrototypeOf
Object.isExtensible
Object.preventExtensions
Object.getOwnPropertyDescriptor
Object.defineProperty
the delete operator
Object.getOwnPropertyNames (Symbols)
function call
the new operator
.has()
.get()
.set()
.getPrototypeOf()
.setPrototypeOf()
.isExtensible()
.preventExtensions()
.getOwnPropertyDescriptor()
.defineProperty()
.deleteProperty()
.ownKeys()
.apply()
.construct()
prop in target
target[prop]
target[prop] = newValue
Object.getPrototypeOf
Object.setPrototypeOf
Object.isExtensible
Object.preventExtensions
Object.getOwnPropertyDescriptor
Object.defineProperty
delete target[prop]
Object.getOwnPropertyNames (Symbols)
target[prop].apply()
new target()
和 proxy 可以代理的行為一對一對應
Reflect.has(person, 'name') =
'name' in person
const personYouSee = new Proxy(person, {
get(target, prop) {
if (prop === 'name') return 'Bob';
return Reflect.get(target, prop);
}
};
定義行為
定義屬性
const person = {
_name = 'Bob',
};
console.log(person._name); // Bob
function funcA() {
const scoped = 'secret';
function funcB() {
console.log(scoped);
}
return funcB;
}
const printSecret = funcA();
printSecret(); // secret
閉包(Closure)是函式以及該函式被宣告時所在的作用域環境(lexical environment)的組合。(MDN)
Operationally, a closure is a record storing a function[a] together with an environment. (Wikipedia)
function Person() {
const name = 'Bob';
this.greet = function() {
console.log(`Hi, I'm ${name}.`);
};
}
const person = new Person();
person.greet(); // Hi, I'm Bob.
ES6
1. collection of key/value pairs
2. key 一定要是 object,value 隨意
3. keys are weakly referenced
const person = {};
const weakMap = new WeakMap();
weakMap.set(person, 'someValue');
console.log(weakMap.get(person)); // someValue
weakMap.delete(person);
console.log(weakMap.has(person)); // false
let person = {};
const weakMap = new WeakMap();
weakMap.set(person, 'someValue');
console.log(weakMap.get(person)); // someValue
person = null;
// 不需要先 weakMap.delete(person),
// 原來的 person/value pair 之後也會消失,
// 不會造成某種形式的 memory leak
keys are weakly referenced
const Person = (function () {
const privateProps = new WeakMap();
class Person {
constructor() {
privateProps.set(this, { name: 'Bob' });
}
greet() {
console.log(`Hi, I'm ${privateProps.get(this).name}.`);
}
}
return Person;
})();
const person = new Person();
person.greet(); // Hi, I'm Bob.
立即函式 (Immediately Invoked Function Expression)
const privateProps = new WeakMap();
class Person {
constructor() {
privateProps.set(this, { name: 'Bob' });
}
greet() {
console.log(`Hi, I'm ${privateProps.get(this).name}`);
}
}
export default Person;
const key = Symbol();
const object = {
[key]: '1234',
};
console.log(object[key]); // 1234
什麼是 Symbol?
ES6
1. primitive data type
2. every symbol value returned from Symbol() is unique
3. 可以作為 object 的 key
const Person = (function () {
const nameKey = Symbol();
class Person {
constructor() {
this[nameKey] = 'Bob';
}
greet() {
console.log(`Hi, I'm ${this[nameKey]}`);
}
}
return Person;
})();
const person = new Person();
person.greet(); // Bob
const nameKey = Symbol();
class Person {
constructor() {
this[nameKey] = 'Bob';
}
greet() {
console.log(`Hi, I'm ${this[nameKey]}`);
}
}
export default Person;
const nameKey = Symbol();
class Person {
constructor() {
this[nameKey] = 'Bob';
}
greet() {
console.log(`Hi, I'm ${this[nameKey]}`);
}
}
const person = new Person();
console.log(Object.keys(person)); // []
console.log(Object.getOwnPropertyNames(person)); // []
const [sameNameKey] = Object.getOwnPropertySymbols(person);
const instanceYouSee = new Proxy(instance, {
get: function(target, prop, value) {
if (prop.startsWith('_')) throw new Error();
return Reflect.get(target, prop);
},
set: function(target, prop, value) {
if (prop.startsWith('_')) throw new Error();
Reflect.set(target, prop, value);
},
has: function(target, prop) {
return prop.startsWith('_') ? false : Reflect.has(target, prop);
},
};
https://blog.techbridge.cc/2018/05/27/js-proxy-reflect/
class Person {
constructor() {
this._name = 'Bob';
return new Proxy(this, {
get: function(target, prop, value) {
if (prop.startsWith('_')) throw new Error();
return Reflect.get(target, prop);
},
set: function(target, prop, value) {
if (prop.startsWith('_')) throw new Error();
Reflect.set(target, prop, value);
},
has: function(target, prop) {
return prop.startsWith('_') ? false : Reflect.has(target, prop);
},
});
}
}
https://blog.techbridge.cc/2018/05/27/js-proxy-reflect/