面向对象(创建对象)--原型模式03(上)

回顾一下用构造函数模式编写的代码

function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = sayName;
}
function sayName() {
    alert(this.name);
}
var person1 = new Person("Nicholas", 29, "Software Engineer");
var person2 = new Person("Greg", 27, "Doctor"); 

现在我们可以用原型模式进行改写

function Person() {
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function () {
    alert(this.name);
};
var person1 = new Person();
person1.sayName(); //"Nicholas" 
var person2 = new Person();
person2.sayName(); //"Nicholas" 
alert(person1.sayName == person2.sayName); //true 

通过调用构造函数来创建新对象,而且新对象还会具有相同的属性和方法。但与构造函数模式不同的是,新对象的这些属性和方法是由所有实例共享的。

1.理解原型对象

一、基本原理 

a.只要创建了一个新函数(构造函数Person),就会根据一组特定的规则为该函数创建一个 prototype属性,这个属性指向函数的原型对象(Person Prototype)。

b.在默认情况下,所有原型对象都会自动获得一个 constructor(构造函数)属性,这个属性包含一个指向 prototype 属性所在函数的指针。(Person.prototype. constructor 指向 Person 。而通过这个构造函数,我们还可继续为原型对象添加其他属性和方法)。

c.创建了自定义的构造函数之后,其原型对象默认只会取得 constructor 属性;至于其他方法,则都是从 Object 继承而来的。

d.当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象。即 [[Prototype]] ,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。

二、两个方法 

isPrototypeOf() 判断实例的内部的一个指针(内部属性),是否指向构造函数的原型对象。

扫描二维码关注公众号,回复: 3483043 查看本文章
alert(Person.prototype.isPrototypeOf(person1)); //true
alert(Person.prototype.isPrototypeOf(person2)); //true

 Object.getPrototypeOf() 返回的原型对象(Person Prototype),即 [[Prototype]] 的值。

alert(Object.getPrototypeOf(person1) == Person.prototype); //true
alert(Object.getPrototypeOf(person1).name); //"Nicholas"

 三、属性读取

多个对象实例共享原型中的属性和方法的原理是什么?

a.第一次搜索:从对象实例本身开始。如果在实例中找到了具有给定名字的属性,则返回该属性的值,搜索终止;没有找到则继续搜索。(首先,解析器会问:“实例 person1 有 sayName 属性吗?”答:“没有。”然后,它继续搜索)

b.继续搜索:搜索指针指向的原型对象,在原型对象中查找具有给定名字的属性。如果在原型对象中找到了这个属性,则返回该属性的值。(继续搜索,再问:“ person1 的原型有 sayName 属性吗?”答:“有。”于是,它就读取那个保存在原型对象中的函数。)

另外,还要注意以下几点:

当为对象实例添加一个属性时,这个属性就会屏蔽原型对象中保存的同名属性。使用 delete 操作符则可以完全删除实例属性。

  hasOwnProperty() 方法可以检测一个属性是存在于实例中(true),还是存在于原型(false)中。

 

 2. 原型与 in 操作符

 in 操作符使用方式:单独使用和在 for-in 循环中使用。

在单独使用时, in 操作符会在通过对象能够访问给定属性时返回 true ,无论该属性存在于实例中还是原型中

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var person1 = new Person();
var person2 = new Person();
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true
person1.name = "Greg";
alert(person1.name); //"Greg" ——来自实例
alert(person1.hasOwnProperty("name")); //true
alert("name" in person1); //true
alert(person2.name); //"Nicholas" ——来自原型
alert(person2.hasOwnProperty("name")); //false
alert("name" in person2); //true
delete person1.name;
alert(person1.name); //"Nicholas" ——来自原型
alert(person1.hasOwnProperty("name")); //false
alert("name" in person1); //true

同时使用 hasOwnProperty() 方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中,

取得实例和原型中所有可枚举的属性(实例和原型)

在使用 for-in 循环时,返回的是所有能够通过对象访问的、可枚举的(enumerated)属性,其中既包括存在于实例中的属性,也包括存在于原型中的属性。不可枚举的属性有下面几种:

hasOwnProperty() 、 propertyIsEnumerable() 、 toLocaleString() 、 toString() 和 valueOf() 。ECMAScript 5 也将 constructor 和 prototype 属性的 [[Enumerable]] 特性设置为 false 。

取得对象上所有可枚举的实例属性

可以使用 ECMAScript 5 的 Object.keys() 方法。

function Person(){
}
Person.prototype.name = "Nicholas";
Person.prototype.age = 29;
Person.prototype.job = "Software Engineer";
Person.prototype.sayName = function(){
alert(this.name);
};
var keys = Object.keys(Person.prototype);
alert(keys); //"name,age,job,sayName"
var p1 = new Person();
p1.name = "Rob";
p1.age = 31;
var p1keys = Object.keys(p1);
alert(p1keys); //"name,age"

 得到所有实例属性,无论它是否可枚举

var keys = Object.getOwnPropertyNames(Person.prototype);
alert(keys); //"constructor,name,age,job,sayName"

猜你喜欢

转载自blog.csdn.net/jiaojsun/article/details/82900854