Open axlroseart opened 5 years ago
const user = { name: 'pete', age: 28 }
const 声明的对象 user 本身是不能被修改的,比如 user = { name: 'kk' } 但是对象的属性可以修改,比如 user.name = 'kk'
如何设置对象属性也无法被修改: 利用Object.defineProperty
Object.defineProperty(user, 'name', { value: 'pete' })
因为此方法默认对象属性的标志(writable 、enumerable、configurable)都为false writable: 是否只读 enumerable: 是否可枚举 configurable: 是否可配置
let descriptor = Object.getOwnPropertyDescriptor(user, 'name');
alert( JSON.stringify(descriptor, null, 2 ) );
/*
{
"value": "pete",
"writable": false,
"enumerable": false,
"configurable": false
}
*/
属性可以要么是访问器,要么是数据属性,而不能两者都是。 如果我们试图在同一个描述符中提供 get 和 value,则会出现错误:
// Error: Invalid property descriptor.
Object.defineProperty({}, 'prop', {
get() {
return 1
},
value: 2
});
Getter/setter 可以用作“真实”属性值的包装器,以便对它们进行更多的控制。
例如,如果我们想禁止为 user 设置太短的名称,我们可以将 name 存储在一个特殊的 _name 属性中。并在 setter 中过滤赋值操作:
let user = {
get name() {
return this._name;
},
set name(value) {
if (value.length < 4) {
alert("Name is too short, need at least 4 characters");
return;
}
this._name = value;
}
};
user.name = "Pete";
alert(user.name); // Pete
user.name = ""; // Name is too short...
getter 和 setter 背后的伟大设计思想之一 —— 它们允许控制“正常”数据属性并随时调整它。
例如,我们开始使用数据属性 name 和 age 来实现用户对象:
function User(name, age) {
this.name = name;
this.age = age;
}
let john = new User("John", 25);
alert( john.age ); // 25 …但迟早,情况可能会发生变化。我们可能决定存储 birthday,而不是 age,因为它更加精确和方便:
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
}
let john = new User("John", new Date(1992, 6, 1));
现在如何处理仍使用 age 属性的旧代码?
我们可以尝试找到所有这些地方并修复它们,但这需要时间,而且如果该代码是由其他人编写的,则很难做到。另外,age 放在 user 中也是一件好事,对吧?在某些地方,这正是我们想要的。
为 age 添加 getter 可缓解问题:
function User(name, birthday) {
this.name = name;
this.birthday = birthday;
// age 是由当前日期和生日计算出来的
Object.defineProperty(this, "age", {
get() {
let todayYear = new Date().getFullYear();
return todayYear - this.birthday.getFullYear();
}
});
}
let john = new User("John", new Date(1992, 6, 1));
alert( john.birthday ); // birthday 是可访问的
alert( john.age ); // ...age 也是可访问的
(function (root, factory) {
if (typeof define === "function" && define.amd) {
define(["libName"], factory);
} else if (typeof module === "object" && module.exports) {
module.exports = factory(require("libName"));
} else {
root.returnExports = factory(root.libName);
}
}(this, function (b) {})
如果你在库的源码里看到了typeof define,typeof window,或typeof module这样的测试,尤其是在文件的顶端,那么它几乎就是一个UMD库。
;是保证导入的其它 js 脚本,使用工具压缩 js 文件时不出错。一个自执行匿名函数包裹,防止内部变量污染到外部命名空间。阅读过 jQuery 源码的人都知道,jQuery 的也是相同的结构,只是 jQuery 定义的匿名函数多了两个参数 window 和 undefined,然后调用的时候只传入 window,这样,window 可以在 jQuery 内部安全使用,而 undefined 也的确表示未定义(有些浏览器实现允许重定义 undefined)。