这周也是拿到了同程的offer,从此走上了前端之路!感谢我的贵人们。再次纪念一下~!
第11章 不是你的对象不要动
11.1 什么是你的
你的对象:当你的代码创建了这些对象或者你有职责维护其他人的代码的对象时,你就拥有这些对象。
不是你的对象:
- 原生对象(Object、Array等等)
- DOM对象(例如:Document)
- 浏览器对象模型(BOM)对象(例如: window)
- 类库的对象
11.2.1 不覆盖方法
JavaScript这门语言也存在着糟粕,那就是覆盖一个已经存在的方法是难以置信的容易- -即使那个神圣的 document.getElementById()方法也不例外。
// 不好的写法
document.getElementById = function() {
return null; //引起混乱
}
所以这里不做更多的例子,作者以自己的亲身经历告诉我们:不覆盖方法才是明智的选择。
11.2.2 不新增方法
作者举了个Prototype JavaScript类库的发展历史的例子说明了:不新增方法同样也是明智的选择。
11.2.3 不删除方法
删除一个方法有俩种手段:
1、把方法赋值为null
2、使用delete操作符来删除,但是它只能在对象的实例和方法起作用,如果在prototype的属性和方法上使用delete是不起作用的
作者也十分干脆:删除一个已存在对象的方法是糟糕的实践。
11.3 更好的途径
更好的方法就是不直接修改这些对象,而是扩展它,也就是我们通常所说的继承。
JavaScript中有俩种基本的继承方式:基于对象的继承和基于类型的继承。
① 基于对象的继承
ECMAScript5中Object.create()方法是实现这种继承的最简单的方式(如果你不熟悉,《JS权威指南》第121页有详解):
var person = {
name : "Nicholas",
sayName : function() {
alert(this.name);
}
};
var myPerson = Object.create(person);
myPerson.sayName(); // 弹出"Nicholas"
原理:Object.create这个方法会返回一个空函数的实例,这个空函数的原型属性(prototype)是person。同时myPerson.prototype指向了空对象的prototype, 这个空对象的prototype也就是person, 所以当在myPerson上调用sayName函数时,Js会顺着它的原型链向上查找并调用方法。
同时也推荐和感谢慕课网的Bosn老师对于原型和继承这方面的独到、深刻、犀利的讲解!
② 基于类型的继承
基于类型的继承和基于对象的继承工作方式是差不多的,它从一个已存在的对象继承,这里的继承是依赖与原型的。因此,基于类型的继承是通过构造函数实现的,而非对象。这意味着,需要访问被继承对象的构造函数。
function MyError(message) {
this.message = message;
} MyError.prototype = new Error(); // MyError类继承自Error(所谓的超类)。给MyError.prototype赋值为一个Error的实例。然后,每个MyError实例从Error那里继承它的属性和方法, instanceof也能正常工作。
var error = new MyError("Something bad happened.");
console.log(error instanceof Error);
console.log(error instanceof MyError);
11.5 阻止修改
ECMAScript5引入了几个方法来防止对对象的修改。可以做到这样的事情:锁定这些对象,保证任何人不能有意无意地修改他们不想要的功能。以下三种修改的级别:
· 防止扩展 ( preventExtension())
禁止为对象“添加”属性和方法,但已存在的属性和方法是可以被修改或删除的
· 密封 ( seal() )
类似“防止扩展”,而且禁止为对象“删除”已存在的属性和方法
· 冻结 ( freeze() )
类似密封,而且禁止为对象“删除”已存在的属性和方法
每种锁定的类型都拥有俩个方法:一个用来实施操作,另一个用来检测是否应用了相应的操作。
下面的例子中,锁定了prevent对象防止被扩展,所以调用Object.isExtensible()函数返回false,试图为person对象扩展新增属性或方法将会悄无声息的失败。在严格模式下,试图为一个不可扩展的对象新增任何属性或方法都将会抛出一个错误。
var person = {
name : "Nicholas"
}; // 锁定对象
Object.preventExtension(person);
console.log(Object.isExtensible(person)); //false
person.age = 25; //正常情况悄悄地失败,除非在strict模式下抛出错误
原理同上面相似,下面是Object.seal()函数
// 锁定对象
Object.seal(person);
console.log(Object.isExtensible(person)); // false
console.log(Object.isSealed(person)); // true
delete person.name; // 正常情况悄悄地失败,除非在strict模式下抛出错误
person.age = 25; // 同上
使用Object.freeze()函数来冻结一个对象。可以使用Object.isFrozen()函数来检查一个对象是否已被冻结。
// 锁定对象
Object.freeze(person);
console.log(Object.isExtensible(person)); // false
console.log(Object.isSealed(person)); // true
console.log(Object.isFrozen(person)); // true
person.name = "Greg"; // 正常情况下悄悄地失败,除非在strict模式下抛出错误
person.age = 25; // 同上
delete person.name; //同上