JS没法扩展对象的属性-js不可扩展对象、密封对象、冻结对象

发布于 5 年前 作者 nodeper 2052 次浏览 最后一次编辑是 5 年前 来自 分享

JS没法扩展对象的属性

JS中的不可扩展对象、密封对象、冻结对象。

在JavaScript 中,可以对对象的权限进行配置,通过配置,可将对象设置为不可扩展对象、密封对象、冻结对象等,以达到保护对象属性的目的。

javascript中不可扩展对象

如果一个对象可以添加新的属性,则这个对象是可扩展的。Object.preventExtensions()将对象标记为不再可扩展,因此它将永远不会具有超出它被标记为不可扩展的属性。注意,一般来说,不可扩展对象的属性可能仍然可被删除。尝试将新属性添加到不可扩展对象将静默失败或抛出TypeError(最常见但不排除其他情况,如在strict mode中)。 Object.preventExtensions()仅阻止添加自身的属性。但属性仍然可以添加到对象原型。 一旦使其不可扩展,就无法再对象进行扩展。

/*
 * 使用Object.preventExtensions()方法来阻止对象扩展
 * 不可扩展对象不能继续添加新属性与新方法
 * 可以修改原属性与原方法
 */

var obj = {
  a: 'a',
  b: ['b']
};

// 通过Object.preventExtensions()来阻止扩展
Object.preventExtensions(obj);

// 严格模式下报错,非严格模式下静默失败
obj.c = 'c';
console.log(obj);   // { a: 'a', b: [ 'b' ] }

function changeObj() {
  "use strict"
  obj.d = 'd';
  console.log(obj);
} 

try {
  changeObj();
} catch (ex) {
  console.error("error: " + ex.message);    // error: Cannot add property d, object is not extensible
}

// 仍可以修改已有的属性值
obj.a = 'c';
obj.b.push('b2');
console.log(obj);

// 使用Object.isExtensible()可以检测对象是否可扩展
var obj2 = {
  name: "obj2"
}
console.log(Object.isExtensible(obj));    // false
console.log(Object.isExtensible(obj2));    // true 

密封对象

密封对象不可扩展,而且已有的属性成员[[configurable]]特性将被设置成false(意味着不能删除属性和方法,但是可修改已有属性值)

/**
 * 使用Object.seal()可以将对象密封
 * 密封对象不可扩展
 * 已有的属性成员[[configurable]]特性将被设置成false(意味着不能删除属性和方法,但是可修改已有属性值)
 */

let obj = {
  a: 'a',
  b: ['b']
};

Object.seal(obj);

// 非严格模式下静默失败
delete obj.a;
obj.c = 'c';
console.log(obj);   // { a: 'a', b: [ 'b' ] }

// 严格模式下抛出异常
try {
  try {
    (function add_d() {
      "use strict"
      obj.d = 'd';
    })();
  } catch (ex) {
    console.error("add_d:" + ex.message);   // add_d:Cannot add property d, object is not extensible
  } finally {
    (function delete_b() {
      "use strict"
      delete obj.b;
    })();
  }
} catch (ex) {
  console.error('delete_b: ' + ex.message);   // delete_b: Cannot delete property 'b' of #<Object>
}

// 可以修改属性值
obj.a = 'a2';
console.log(obj.a);   // 'a2'

// 通过Object.isSealed()方法可以判断对象是否被密封
let obj2 = {
  name: 'obj2'
};
console.log(Object.isSealed(obj));    // true
console.log(Object.isSealed(obj2));   // false

// 被封闭的对象同时不可扩展
console.log(Object.isExtensible(obj));    // false
console.log(Object.isExtensible(obj2));   // true

冻结对象

最严格的防止篡改级别是冻结对象,冻结的对象既不可以扩展,又是密封的,而且对象数据属性的[[writable]]特性会被设置为false。 如果定义[[Set]]函数,访问器属性仍然是可写的

/**
 * 使用Object.freeze()方法可以冻结对象
 * 冻结对象(frozen object)既不可扩展,又是密封的,而且对象的[[writable]]特性会被设置为false
 * 如果定义[[Set]]函数,访问器属性仍然是可写的
 */

let obj = {
  a: 'a',
  b: ['b']
}

let obj2 = {
  name: 'obj2',
  val: 'hello'
}

// 使用set函数定义一个存取描述符
Object.defineProperty(obj, 'set_obj2', {
  configurable: true,
  enumerable: true,
  get: () => {
    return obj2.val;
  },
  set: (val) => {
    obj2.val = val;
  }
})
// 冻结对象
Object.freeze(obj);

// 非严格模式下静默失败
obj.c = 'c';
console.log(obj.c);   // undefined

delete obj.a;
console.log(obj.a);   // 'a'

obj.a = 'a2';
console.log(obj.a);   // 'a'

// [[set]]函数 访问器属性仍然可写
obj.set_obj2 = 'haha'
console.log(obj.set_obj2);    // 'haha'

// 严格模式下抛出异常
try {
  try {
    (function add_d() {
      "use strict"
      obj.d = 'd';
    })();
  } catch (ex) {
    console.error("add_d:" + ex.message);   // add_d:Cannot add property d, object is not extensible
  } finally {
    (function delete_b() {
      "use strict"
      delete obj.b;
    })();
  }
} catch (ex) {
  console.error('delete_b: ' + ex.message);   // delete_b: Cannot delete property 'b' of #<Object>
}

// 仍然修改obj.b
try {
  (function change_b() {
    "use strict"
    obj.b.push('b2');
    console.log(obj.b);   // [ 'b', 'b2' ]
  })();
} catch (ex) {
  console.error('change_b: ' + ex.message);
}

// 使用Object.isFrozen()方法检测冻结对象
console.log(Object.isFrozen(obj));   // true
console.log(Object.isSealed(obj));   // true
console.log(Object.isExtensible(obj));   // false

console.log(Object.isFrozen(obj2));    // false
console.log(Object.isSealed(obj2));    // false
console.log(Object.isExtensible(obj2));    // true

2 回复

好像用的不多 但是万一遇到就是一个坑

回到顶部