这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战
面向对象(下)
上次我们说到JS该如何判断是this中的函数还是prototype中的函数。该__proto__出马了。
__proto__提供给JS一个链,即原型链。他是对象的独有属性。而他指向的是对象原型的prototype。
function Person(name){
this.name = name;
}
Person.prototype.say = function(){
console.log("say Something..");
};
var personA = new Person("A");
console.log(personA.__proto__ === Person.prototype); //true
这样在personA这个实例中,就不只有constructor与Person产生联系,我们还有__proto__。
那么在personA调用方法的时候,他会先去检查是不是自己的属性。
JS也提供了判断的方法hasOwnProperty()是否是自己的属性
personA.hasOwnProperty("say");//false
然后再通过__proto__获取Person.prototype检查是否有该属性。
Person.prototype.hasOwnProperty("say"); //true
可能有同学会问,如果在Person.prototype中也没用这个属性呢?
前面提到__proto__就是提供原型链方法调用查询的。而__proto__是每个对象都独有的属性,所以Person.prototype他也是有__proto__属性。我们继续调用看看。
console.log(Person.prototype.__proto__);
/**
{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
__proto__: (...)
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
*/
在浏览器中我们可以看到这么一大坨东西。这到底是什么呢?
我们在其中可以发现一个很熟悉的属性constructor。
那么好,我们可以知道他是谁创建的了。
console.log(Person.prototype.__proto__.constructor);
//返回 ƒ Object() { [native code] }
答案很明细,他是Object创建的对象。而他就是Object.prototype
console.log(Person.prototype.__proto__ === Object.prototype ); // true
那么如果再继续呢?
console.log(Object.prototype.__proto__);// null
为空!那么当我们输入一个从personA到Object都不存在的方法或者对象时,浏览器就会返回Uncaught TypeError或者undefined。
这样我们脑海里应该有一条清晰的链
[personA] --(__proto__)--》 [Person.prototype] --(__proto__)--》 [Object.prototype] --(__proto__)--》 null
这就是原型链。
通过这么一条原型链,我们回头看personA.constructor的时候,我们可以发现,personA调用的constructor,其实是Person.prototype中的constructor。
console.log(personA.constructor === Person.prototype.constructor);//true
那么其实任何一个prototype对象都有一个constructor属性,指向它的构造函数。
面向对象总结
我们可以理解到在JS中主要就是由三个属性帮助我们构建面向对象。
constructorprototype__proto__
我们的总结也可以分成三条
- 当我们创建对象或者想知道该对象被谁创建,使用
constructor构造函数。 - 当我们需要挂载一个统一的方法或者属性,我们使用
prototype挂载方法或者属性。他是函数独有的,而我们的函数也恰好是对象。 - 当我们搜索属性或者方法的时候,调用
__proto__,他是对象独有的。
根据上面的三条。
我们按照personA的案例可以画出一个比较清晰的图...