《JS高级程序设计》第6章的读书笔记
- 创建对象(一)工场模式和构造函数模式
- 创建对象(二)原型模式和组合模式
- 创建对象(三)再探原型
- 对象继承(一)原型链
- 对象继承 (二)借用构造函数和组合继承
- 对象继承(三)原型式继承和寄生式继承
- 对象继承(四)寄生组合式继承
###1 前言
其实,在 上一篇博客:《JS高级程序设计》第6章读书笔记:创建对象(二)原型模式和组合模式,我们讨论了原型了模式,但是关于原型,我们还没讲完。
这一节,我们讨论原型的一些细节。
###2 原型与in操作符
在单独使用in
操作符时,如果能够通过对象访问给定属性,无论是是通过原型还是实例,则会返回true
function Person() {}
Person.prototype.name = 'Nicholas';
Person.prototype.age = '29';
let p1 = new Person();
console.log('name' in p1); //true
p1.name = 'hhhha';
console.log('name' in p1); //true
delete p1.name1
从上述代码看出,可以无论是通过实例,还是原型访问属性name
, 调用 name in p1 都返回true。
根据Object.hasOwnProperty()接口和in 操作符可以间接判断一个属性是否存在于原型。
//判断一个属性是否是原型属性
function hasPrototypeProperty(object, name) {
return !object.hasOwnProperty(name) && (name in object);
}
function Person() {}
Person.prototype.name = 'achao';
Person.prototype.getName = function() {
return this.name;
}
p1 = new Person();
console.log(hasPrototypeProperty(p1, 'name'));//true
for-in 循环
for-in循环时,返回的是能够通过对象访问的,可枚举的属性,不仅是实例属性,还是原型属性(包括屏蔽了原型中不可枚举的的实例,但是I8及其IE8-是例外,而这是违反规范的。)
//for-in 循环屏蔽原型属性的实例属性
var o = {
toString: function() {
return 'my object';
}
}
for (var prop in o) {
if (prop == 'toString') {
console.log("found tostring");
}
}
Object.keys()
Object.keys()获取对象上所有可枚举的实例属性或者原型属性
function Person() {}
Person.prototype.name = 'achao';
Person.prototype.getName = function() {
return this.name;
}
p2 = new Person();
p2.name = 'yujie';
//Object.keys()获取实例对象上所有可枚举的实例属性或者原型的所有可枚举的原型属性,分别传入原型对象和实例对象
var keys = Object.keys(Person.prototype);
console.log(keys); // ['name','getName']
var p2keys = Object.keys(p2);
console.log(p2keys);//['name']
Object.getOwnPropertyName()
这个方法可以获取原型对象的所有属性,且无论是否可以枚举。传入参数为原型对象
var allkeys = Object.getOwnPropertyNames(Person.prototype);
console.log(allkeys);
//['constructor','name','getName']
###3 原型的动态性
重写原型会不能建立实例对象和新原型对象之间的联系,而且切断了构造函数与旧原型对象之间的联系。
看下面这段代码。
function Person() {}
var friend = new Person();
Person.prototype = {
constructor: Person,
name: 'Nicholas',
age: 29,
job: "Software Engineer",
sayName: function() {
console.log(this.name);
}
}
friend.sayName(); //friend.sayName is not a function
下图清晰地描述上面代码重写原型后的结果:实例对象的[[prototype]]属性还是指向旧原型对象,不是新原型对象;新构造函数的prototype属性不再指向旧原型对象。
所以friend实例不能访问到新原型对象的方法。
###4 原生对象的原型
所有原生引用类型都是通过原型模式创建的。所有原生类型(Oject,Array,String等等)都原型对象上定义了方法。如Array.prototype.splice()
像自定义类型一样,原生类型的属性也可以被修改和增加。
例子可以看:这篇博文