在工作中有时候会看到prototype和__proto__这两个属性,对这两个属性我一直比较蒙圈,但是我通过查阅相关资料,决定做一下总结加深自己的理解,写得不对的地方还请各位大神指出。
跟__proto__属性相关的两个方法
判断属性是存在实例对象中,还是存在原型对象中的方法
获取或遍历对象中属性的几种方法
1、prototype
每个函数都有一个prototype属性,该属性是一个指针,指向一个对象。 而这个对象的用途是包含由特定类型的所有实例共享的属性和方法。使用这个对象的好处就是可以让所有实例对象共享它所拥有的属性和方法
2、 __proto__
每个实例对象都有一个__proto__属性,用于指向构造函数的原型对象。__proto__属性是在调用构造函数创建实例对象时产生的。
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; this.sayName = function(){ console.log(this.name); }; // 与声明函数在逻辑上是等价的 } var person1=new Person("Nicholas",29,"Software Engineer"); console.log(person1); console.log(Person); console.log(person1.prototype);//undefined console.log(person1.__proto__); console.log(Person.prototype); console.log(person1.__proto__===Person.prototype);//true
输出结果如下:
总结:
1、调用构造函数创建的实例对象的prototype属性为"undefined",构造函数的prototype是一个对象。
2、__proto__属性是在调用构造函数创建实例对象时产生的。
3、调用构造函数创建的实例对象的__proto__属性指向构造函数的prototype。
4、在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype属性所在函数的指针。
下图展示了使用Person构造函数创建实例后各个对象之间的关系
上图展示了 Person 构造函数、 Person 的原型属性以及 Person现有的两个实例之间的关系。
3、 跟__proto__属性相关的两个方法
isPrototypeOf():虽然在所有实现中都无法访问到__proto__,但可以通过 isPrototypeOf()方法来确定对象之间是否存在这种关系。
alert(Person.prototype.isPrototypeOf(person1)); //true alert(Person.prototype.isPrototypeOf(person2)); //true
Object.getPrototypeOf():在所有支持的实现中,这个方法返回__proto__的值。例如:
alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name); //"Nicholas"
注意:虽然可以通过对象实例访问保存在原型中的值,但却不能通过对象实例重写原型中的值。如果我们在实例中添加了一个属性,而该属性与实例原型中的一个属性同名,那我们就在实例中创建该属性,该属性将会屏蔽原型中的那个属性。请看下面的例子:
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(); person1.name = "Greg"; alert(person1.name); //"Greg"—— 来自实例 alert(person2.name); //"Nicholas"—— 来自原型
4、 判断属性是存在实例对象中,还是存在原型对象中,有以下方法
hasOwnProperty():可以检测一个属性是存在于实例中,还是存在于原型中。返回值为true表示该属性存在实例对象中,其他情况都为false。
in 操作符:无论该属性存在于实例中还是原型中。只要存在对象中,都会返回true。但是可以同时使用 hasOwnProperty()方法和 in 操作符,就可以确定该属性到底是存在于对象中,还是存在于原型中。
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
5、 获取或遍历对象中属性的几种方法
for-in:通过for-in循环的返回的是能够被访问的、可枚举的属性,不管该属性是在实例中,还是存在原型中。