共计 2493 个字符,预计需要花费 7 分钟才能阅读完成。
前言
开篇先记住以下两点,再慢慢通过实例了解
__proto__
和constructor
属性是 对象 所独有的;prototype
属性是 函数 所独有的。
然而因为 JS
中函数也是一种对象,所以函数也领有 __proto__
和 constructor
属性
一、函数的原型对象
咱们创立函数 A
的同时, 浏览器会在内存中创立一个对象 B
,A
函数默认会有一个 prototype
属性。指向了对象 B
(即:prototype
的属性的值是对象 B
)。 这个对象 B
就是函数 A
的原型对象,简称函数的原型。 原型对象 B
默认会有一个属性 constructor
指向了函数 A
(即 constructor
属性的值是函数 A
)。 原型对象默认只有属性 constructor
。其余都是从 Object
继承而来。
正式开始:举栗子探讨
// 创立一个构造函数 Foo(),并用 new 关键字实例化该构造函数失去一个实例化对象 f1。function Foo() {...};
let f1 = new Foo();
二、proto 属性
__proto__
属性,它是 对象所独有的 ,能够看到__proto__
属性都是由 一个对象指向一个对象,即指向它们的原型对象(也能够了解为父对象),那么这个属性的作用是什么呢?
它的 作用 就是当拜访一个对象的属性时,如果该对象外部不存在这个属性,那么就会去它的 __proto__
属性所指向的那个对象(能够了解为父对象)里找,如果父对象也不存在这个属性,则持续往父对象的 __proto__
属性所指向的那个对象(能够了解为爷爷对象)里找,如果还没找到,则持续往上找…. 直到原型链顶端 null。
此时若还没找到,则返回 undefined
。以上这种通过__proto__
属性来连贯对象直到 null
的一条链即为咱们所谓的 原型链。
三、prototype 属性
prototype
是 函数所独有的 ,它是从 一个函数指向一个对象。
它的含意是 函数的原型对象,也就是这个函数所创立的实例的原型对象,由此可知:
f1.__proto__ === Foo.prototype
prototype
属性的 作用:
它的 作用 就是蕴含能够由特定类型的所有实例共享的属性和办法,也就是让该函数所实例化的对象们都能够找到专用的属性和办法。
四、constructor 属性
constructor属性也是 对象才领有的 ,它是从 一个对象指向一个函数 ,含意就是 指向该对象的构造函数 ,每个对象都有构造函数,从图中能够看出**Function**
这个对象比拟非凡,它的构造函数就是它本人(因为 Function
能够看成是一个函数,也能够是一个对象),所有函数最终都是由 Function()
构造函数得来,所以constructor 属性的起点就是 Function()。
举例子
// 创立构造函数
function Person () {}
// 应用 Person.prototype 间接拜访到原型对象
// 给 Person 函数的原型对象中增加一个属性 name,值是 "张三"
Person.prototype.name = "张三";
// 创立一个实例 p1
var p1 = new Person();
// 拜访 p1 对象的属性 name,尽管在 p1 对象中咱们并没有明确的增加属性 name,然而 p1 的 prototype 属性指向的原型中有 name 属性,所以这个中央能够拜访到属性 name 值。alert(p1.name); // 张三
var p2 = new Person();
alert(p2.name); // 张三 都是从原型中找到的,所以一样。alert(p1.name === p2.name); // true
// 因为不能批改原型中的值,上面这种办法就间接在 p1 中增加了一个新的属性 name,而后在 p1 中无奈再拜访到原型中的属性。p1.name = "李四";
alert("p1:" + p1.name);
// 对 p2 来说依然是拜访的原型中的属性。alert("p2:" + p2.name); // 张三
// 如何证实证实 p1.__proto__ 与 Person.prototype 是雷同的
alert(p1.__proto__ === Person.prototype); //true
五、罕用办法
hasOwnProperty()
与 in
操作符
作用:判断函数的原型所在位置
function Person () {};
Person.prototype.name = "志玲";
var p1 = new Person();
p1.sex = "女";
// 定义一个函数去判断原型所在的地位
function propertyLocation(obj, prop){if(!(prop in obj)){alert(prop + "属性不存在");
}else if(obj.hasOwnProperty(prop)){alert(prop + "属性存在于对象中");
}else {alert(prop + "对象存在于原型中");
}
}
propertyLocation(p1, "age"); //age 属性不存在
propertyLocation(p1, "name"); //name 对象存在于原型中
propertyLocation(p1, "sex"); //sex 属性存在于对象中
六、动静原型模式创建对象
// 构造方法外部封装属性
function Person(name, age) {
// 每个对象都增加本人的属性
this.name = name;
this.age = age;
/*
判断 this.eat 这个属性是不是 function,如果不是 function 则证实是第一次创建对象,则把这个 funcion 增加到原型中。如果是 function,则代表原型中曾经有了这个办法,则不须要再增加。perfect!完满解决了性能和代码的封装问题。*/
if(typeof this.eat !== "function"){Person.prototype.eat = function () {alert(this.name + "在吃");
}
}
}
var p1 = new Person("志玲", 40);
p1.eat(); // 志玲 在吃
作者:炒面熊
链接:https://juejin.im/post/6894157108904722439
起源:掘金