Vue不兼容IE8原因以及Object.defineProperty詳解
原因概述:
- Vue.js使用了IE8不能模擬的ECMAScript5特性. Vue.js支持所有兼容ES5的瀏覽器.
- Vue將遍歷此對象所有的屬性, 並使用Object.defineProperty把這些屬性全部轉為getter/setter.
- Object.defindProperty是僅ES5支持, 且無法shim的特性.
接下來逐步介紹概念.
shim特性
指把一個庫引入一個舊的瀏覽器, 然后用舊的API, 實現一些新的API的功能.
Object.definePropety()
- 語法:
Object.definePropety(obj, prop, descriptor)
- 參數:
- obj: 操作對象
- prop: 需要操作的屬性名稱
- descriptor: 屬性具有的特性
- 返回值: 傳入的對象, 即第一個參數obj
- 針對特性描述存在兩種形式: 數據描述和存取器描述
數據描述
當修改或定義對象的時候, 給屬性添加一些特性
var obj = {
test: 'hello'
}
// 對象已有的屬相添加特性描述
Object.defineProperty(obj, 'test', {
configurable: true | false,
enumerable: true | false,
value: `任意類型的值`,
writable: true | false
})
// 對象新添加的屬性描述
Object.defineProperty(obj, 'newKey', {
configurable: true | false,
enumerable: true | false,
value: `任意類型的值`,
writable: true | false
})
value
- 屬性對應的值, 可以為任意類型的值.
- 默認:
undefined
// 不設置value的值
Object.defineProperty(obj, 'newKey', {
})
console.log(obj.newKey) // undefined
/*
注: 兩段代碼不能同時出現 ;
報錯: Cannot redefine property: newKey
原因: configurable屬性默認為false, 不能修改; writable默認fasle, 不能被重寫
*/
// 設置value值
Object.defineProperty(obj, 'newKey', {
value: 'this is test'
})
console.log(obj.newKey) // undefined
writable
- 屬性的是否可以被重寫.
- 默認false, 不能被重寫.
// writable為false, 不可被重寫
Object.defineProperty(obj, 'newKey', {
value: 'hello',
writable: false
})
Object.defineProperty(obj, 'newKey', {
value: 'change'
})
// 這種情況下會報錯: Cannot redefine property: newKey
console.log(obj.newKey)
// 可以被重寫
Object.defineProperty(obj, 'newKey', {
value: 'hello',
writable: false
})
obj.newKey = 'change'
console.log(obj.newKey) // hello
enumerable
- 此屬性是否可以枚舉(使用for...in或者Object.keys)
- 默認為false: 不可枚舉
// 不可枚舉
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello'
})
console.dir(obj) // {}
// 可以枚舉
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello',
enumerable: true
})
console.dir(obj) // { newKey: 'hello' }
configurable
- 目標屬性是否可以被刪除
- 目標屬性的特性是否可以被再次修改
- 默認false, 不可刪除與修改
// 屬性不可被刪除
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello',
configurable: false
})
delete obj.newKey
console.log(obj.newKey) // hello
// 屬性可以被刪除
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello',
configurable: true
})
delete obj.newKey
console.log(obj.newKey) // undefined
// 不能修改特性
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello',
writable: false,
configurable: false
})
Object.defineProperty(obj, 'newKey', {
writable: true,
})
// 報錯: Cannot redefine property: newKey
// 再次修改特性
var obj = {}
Object.defineProperty(obj, 'newKey', {
value: 'hello',
writable: false,
configurable: true
})
Object.defineProperty(obj, 'newKey', {
writable: true,
})
obj.newKey = 'change'
console.log(obj.newKey) // change
注意
- 一旦使用Objec.defineProperty給對象添加屬性, 如果不設置屬性的話, 那么configuable, enumerable, writable這些都是默認的false
- 不能被枚舉, 不能被重寫, 不能被再次更改屬性
存取器描述
當使用存取器描述特性的時候, 允許使用以下特性屬性:
var obj = {}
Object.defineProperty(obj, 'newKey', {
get: function() {} | undefined,
set: function() {} | undefined,
configurable: true | false,
enumerable: true | false
})
- 當使用了getter或者setter方法, 不允許使用
writable
和value
這兩個屬性
getter/setter
- 當設置或獲取某個對象的屬性值的時候, 可以提供getter/setter方法
- getter: 是一種獲取值的方法
- setter: 是一種設置值的方法
// 在特性中使用get/set屬性來定義對應的方法
var obj = {}
var initVlue = 'hello'
Object.defineProperty(obj, 'newKey', {
get: function () {
// 當獲取值的時候, 觸發這個函數
return initVlue
},
set: function (value) {
// 設置值的時候, 觸發這個函數
initVlue = value
}
})
// 獲取值
console.log(obj.newKey) // hello
obj.newKey = 'change'
console.log(initVlue)// change
- get/set不必成對出現, 任寫其一就可以. 如果設置不方便, 則get和set的默認值為undeifend
兼容性
在IE8下只能對DOM對象使用, 如果對原生對象使用Object.defineProtry()會報錯