Object-Oriented(二)原型对象
自用备忘笔记
1. 理解原型对象
只要创建函数,函数上就会创建一个 prototype 属性指向函数的原型对象。
function Person() {}
Person.prototype //指向该函数的原型对象
所有原型对象会自动获得一个 constructor 属性指向 prototype 属性所在的函数。
Person.prototype.constructor === Person; //true
每个通过构造函数生成的实例对象,都包含一个 [[Prototype]] 属性指向其构造函数的原型对象,在 Firefox、Safari 和 Chrome 中可以通过 __proto__ 来访问。
var Daryl = new Person();
Daryl.__proto__ === Person.prototype; //true
虽然无法通过标准的方法访问 [[Prototype]] 方法,但可以通过 isPrototypeOf() 方法来确实关系。
Person.prototype.isPrototypeOf(Daryl); //true
ES5新增了一个方法:Object.getPrototypeOf(),该方法可以返回 [[Prototype]] 的值。
Object.getPrototypeOf(Daryl) === Person.prototype; //true
虽然通过实例对象可以访问原型中的属性,但无法通过实例对象重写原型中的属性。
function Person() {}
Person.prototype.name = 'Daryl'; var person1 = new Person(),
person2 = new Person(); person1.name = 'Nicholas';
person1.name; //Nicholas
person2.name; //Daryl
对对象属性的访问,是先检索实例上有无该属性,再检索原型对象上有无该属性。若删除实例上的属性,则会恢复对原型对象属性的访问。
person1.name = 'Nicholas';
delete person1.name;
person1.name; //Daryl
通过 hasOwnProperty 方法可以检测某个属性究竟来自实例还是原型。
person1.name = 'Nicholas';
person1.hasOwnProperty('name'); //true
person2.hasOwnProperty('name'); //false
2. 原型与 in 操作符
in 操作符用来检测某个对象中是否有某个属性,可以单独使用,也可以搭配 for 使用。
person1.name = 'Nicholas';
'name' in person1; //true
'name' in person2; //true
使用 for-in 遍历对象的属性时会将原型上的属性一起遍历,如果需要滤掉这部分,可以搭配 hasOwnProperty 方法一起使用。
function Person() {}
Person.prototype.name = 'Nicholas';
var person = new Person();
person.age = 29;
person.gender = 'male'; for (var o in person) {
if (person.hasOwnProperty(o)) {
console.log(o); //age, gender
}
}
ES5新增了 Object.keys 方法,用来返回一个所有可枚举的实例属性的集合。
Object.keys(person); //['age', 'gender']
如果想要得到所有的属性,无论是否可枚举,可以使用 Object.getOwnPropertyNames。
Object.getOwnPropertyNames(Person.prototype); //['constructor', 'name']
以上两种方法都可以用来代替 for-in 循环。
3. 更简单的原型语法
为了避免重复书写,可以通过对象字面量的方式重写原型对象。
function Person() {}
Person.prototype = {
name: 'Nicholas',
age: 29,
sayName: function() {
alert(this.name);
}
};
这种方式会导致原型对象上的 constructor 属性丢失,可以手动指定 constructor 属性。
function Person() {}
Person.prototype = {
constructor: Person,
name: 'Nicholas',
age: 29,
sayName: function() {
alert(this.name);
}
};
但 constructor 本身是不可枚举的,可以通过 ES5 新增的 Object.defineProperty() 方法设置。
Object.defineProperty(Person.prototype, 'constructor', {
enumerable: false,
value: Person
});
4. 原型的动态性
由于在原型中查找值的过程是一次搜索,因此在任何时候对原型对象的修改都会立即反映在实例上。
var Daryl = new Person();
Person.prototype.sayHi = function() {
alert('Hi');
};
Daryl.sayHi(); //Hi
但是重写原型对象会导致构造函数与原型之间的联系被切断。
var Daryl = new Person();
Person.prototype = {
sayHi: function() {
alert('Hi');
}
};
Daryl.sayHi(); //出错
5. 原生对象的原型
原型模式不仅应用在自定义类型方面,就连所有原生的引用类型,都是采用这种模式创建的。它们都在其构造函数的原型上定义了方法。
Array.prototype.sort; //function
String.prototype.substring; //function
还可以在原生对象上定义新方法,如下,定义一个反转字符串的方法。
String.prototype.reverseString = function() {
return this.split('').reverse().join('');
}; 'Hello World!'.reverseString(); //!dlroW olleH
6. 原型的问题
由于原型上所有属性均是共享的,若某个实例对原型中的引用类型属性进行修改,则这一个修改会反映在所有实例上。
function Person() {}
Person.prototype.friends = ['Shelby', 'Court']; var person1 = new Person(),
person2 = new Person(); person1.friends.push('Van');
person2.friends; //['Shelby', 'Court', 'Van'];
最新文章
- (五)Maven目录结构及常用命令说明
- php大力力 [040节] 买了一天域名,整了一天后台,新网后台不懂啊
- C#父类子类对象关系
- Spring MVC 环境搭建(二)
- ionic使用sass
- Oracle 中 for update 和 for update nowait 的区别
- uva 1421
- GAC的理解及其作用
- 如何在google test中指定只运行一部分测试
- Mac上利用Eclipse编译Cocos2d-x
- usaco1.1.1Your Ride Is Here(入门题)
- JavaScript 加号运算符详解
- jQuery和AngularJS的区别
- 需求分析&;原型设计
- node-RED
- Android--多线程之AsyncTask
- 在linux上安装Scala详细步骤
- 分类统计的controller和service
- MySQL实现树状所有子节点查询的方法
- JVM(上)
热门文章
- 【js基础】js排序方法——快排+堆排+插排+选择排
- django静态文件
- go xorm增删改查
- MySQL 1130 - Host 127.0.0.1 is not allowed to connect to this MySQL server
- 使用Maven分环境打包:dev sit uat prod
- 基础数据类型之AbstractStringBuilder
- 3.定时器的使用(以通俗易懂的语言解释JavaScript)
- CRM项目之stark组件(2)
- ByteArrayInputStream与ByteArrayOutputStream_操作数组的流
- Android应用启动、退出分析