函數名
有兩種特殊情況:bind方法創造的函數,name屬性返回bound加上原函數的名字;Function構造函數創造的函數,name屬性返回anonymous。
- bind函數名
// 以bound開頭
function foo() { }
const fnName = foo.bind().name
console.log(fnName) // bound foo
- getter setter
如果對象的方法使用了取值函數(getter)和存值函數(setter),則name屬性不是在該方法上面,而是該方法的屬性的描述對象的get和set屬性上面,返回值是方法名前加上get和set。
const obj = {get foo() {},set foo(x) {}
};obj.foo.name
// TypeError: Cannot read property 'name' of undefinedconst descriptor = Object.getOwnPropertyDescriptor(obj, 'foo');descriptor.get.name // "get foo"
descriptor.set.name // "set foo"
對象方法的簡寫
const o = {method() {return "Hello!";}
};
- node common.js寫法+
屬性名表達式
ES6 允許字面量定義對象時,用方法二(表達式)作為對象的屬性名,即把表達式放在方括號內。
let propKey = 'foo';let obj = {[propKey]: true,['a' + 'bc']: 123
};
let obj = {['h' + 'ello']() {return 'hi';}
};obj.hello() // hi
- 屬性名可以重復,重復則覆蓋
let b = 'b'
let obj = {['a' + 'b'] : undefined,['a' + b] : 1, // 屬性名和上面重復,永遠取最后的,obj最后依然只有一個鍵‘ab’
}
屬性名表達式如果是一個對象,默認情況下會自動將對象轉為字符串[object Object],這一點要特別小心。
const keyA = {a: 1};
const keyB = {b: 2};const myObject = {[keyA]: 'valueA',[keyB]: 'valueB'
};myObject // Object {[object Object]: "valueB"}
// 1. 屬性名相同覆蓋
// 2. 將一切js變量轉為字符串,作為屬性名
- 一個對象的屬性名可以是任何有效的 JavaScript 字符串,或者可以被轉換為字符串的任何類型,包括空字符串。然而,一個屬性的名稱如果不是一個有效的 JavaScript 標識符(例如,一個由空格或連字符,或者以數字開頭的屬性名),就只能通過方括號標記訪問。這個標記法在屬性名稱是動態判定(屬性名只有到運行時才能判定)時非常有用。
- JavaScript中的對象只能使用String類型作為鍵類型。
屬性描述符
getOwnPropertyDescriptor
是構造器上的方法- 方法返回指定對象上一個自有屬性對應的屬性描述符。(自有屬性指的是直接賦予該對象的屬性,不需要從原型鏈上進行查找的屬性)若無返回
undefined
Object.getOwnPropertyDescriptor(obj, prop)
一個屬性描述符是一個記錄,由下面屬性當中的某些組成的:
- value
該屬性的值(僅針對數據屬性描述符有效)- writable
當且僅當屬性的值可以被改變時為true。(僅針對數據屬性描述有效)
重新賦值,不包括刪除!
- get
獲取該屬性的訪問器函數(getter)。如果沒有訪問器, 該值為undefined。(僅針對包含訪問器或設置器的屬性描述有效)- set
獲取該屬性的設置器函數(setter)。 如果沒有設置器, 該值為undefined。(僅針對包含訪問器或設置器的屬性描述有效)- configurable
當且僅當指定對象的屬性描述可以被改變或者屬性可被刪除時,為true。
delete obj.a
- enumerable
當且僅當指定對象的屬性可以被枚舉出時,為 true。
Object.defineProperty(o, "baz", {value: 8675309,writable: false, // 重寫baz屬性會靜默失敗;而嚴格模式重寫則報錯enumerable: false
});
- 注意:在 ES5 中,如果該方法的第一個參數不是對象(而是原始類型),那么就會產生出現 TypeError。而在 ES2015,第一個的參數不是對象的話就會被強制轉換為對象。
Object.getOwnPropertyDescriptor('foo', 0);
// 類型錯誤: "foo" 不是一個對象 // ES5 codeObject.getOwnPropertyDescriptor('foo', 0);
// Object returned by ES2015 code: {
// configurable: false,
// enumerable: true,
// value: "f",
// writable: false
// }
getter、setter在對象上
使用Object.defineProperties的方法,同樣也可以對一個已創建的對象在任何時候為其添加getter或setter方法。這個方法的第一個參數是你想定義getter或setter方法的對象,第二個參數是一個對象,這個對象的屬性名用作getter或setter的名字,屬性名對應的屬性值用作定義getter或setter方法的函數。
- set必須要有參數,否則報錯
Uncaught SyntaxError: Setter must have exactly one formal parameter.
var o = {a: 7,get b() { return this.a + 1;},set c(x) {this.a = x / 2}
};console.log(o.a); // 7
console.log(o.b); // 8 注意訪問方式 get直接讀
o.c = 50; // set要賦值
console.log(o.a); // 25
var language = {set add(name){this.ln.push(name)},ln: []
}
language.add = 'EN'
language.add = 'FN'
console.log(language.ln) // ["EN","FN"]
mdn getter
mdn setter
- a也是o的屬性,只是用getter、setter劫持了
- 如果getter和屬性重名,會報錯 Uncaught RangeError: Maximum call stack size exceeded
不可能同時將一個 getter 綁定到一個屬性并且該屬性實際上具有一個值。
使用get語法時,不能與另一個 get 或具有相同屬性的數據條目同時出現在一個對象字面量中。
不允許使用 { get x() { }, get x() { } } 和 { x: …, get x() { } })。
在對象字面量中,不能為一個已有真實值的變量使用 set ,也不能為一個屬性設置多個 set。
( { set x(v) { }, set x(v) { } } 和 { x: …, set x(v) { } } 是不允許的 )
var o = {_a: 7,get a() { return this._a + 1;},set a(x) {this._a = x / 2}
};console.log(o.a); // 8
o.a = 10
console.log(o.a); // 6
console.log(Object.keys(o)) // ["_a","a"]
Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #<Object>
var obj = {get a(){return 2}
}
// 注意:這里也不能再為已有的對象屬性,使用defineProperty
Object.defineProperty(obj, 'b', {get: function(){return this.a + 100},// value: 2 寫了get不能再寫value/writable,否則報錯
})
console.log(obj.a) // 2
console.log(obj.b) // 102
- get和set一般是成對出現的,并且不應寫死,不然沒有意義
getter/setter → 偽屬性
- Object.defineProperty與創建對象時定義getter/setter的區別
- Object.defineProperty的getter/setter/其余普通屬性不可枚舉、不可配置
const obj = {a: 2
}
Object.defineProperty(obj, 'b', {set: function (x) {this.a = x}
})
const res = Object.getOwnPropertyDescriptor(obj, 'b')
console.log(res)
console.log(Object.keys(obj))const obj2 = {_a: 2,get a() {return this._a},set a(val) {this._a = val}
}
const res2 = Object.getOwnPropertyDescriptor(obj2, 'a')
console.log(res2)
console.log(res2.get.name) // get a
console.log(res2.set.name) // set a
console.log(Object.keys(obj2))