一些原型的理解(2)
关于原型的一些理解
-
函数的prototype属性
-
每个函数都有一个prototype属性,即显式原型(属性), 它默认指向一个Object空对象(即称为: 原型对象)
-
原型对象中有一个属性constructor, 它指向函数对象
-
原型对象还有一个__proto__属性,这是实例对象都有的属性,可称为隐式原型(属性),对象的隐式原型的值为其对应构造函数的显式原型的值
function fn(name) { this.name = name } console.log(fn.prototype) -------------------------------------------- { constructor: ƒ fn(name) __proto__: Object }
-
-
给原型对象添加属性(一般都是方法)
- 作用: 函数的所有实例对象自动拥有原型中的属性(方法)
-
函数的prototype属性: 在定义函数时自动添加的, 默认值是一个空Object对象
对象的__proto__属性: 创建对象时自动添加的, 默认值为构造函数的prototype属性值
-
所有函数都是Function的实例(包含Function自己),所以所有函数既可以是构造函数也可以是实例对象,也就是说所有函数中中既有__proto__也有prototype
console.log(fn.__proto__ === Function.prototype) //true console.log(Function.__proto__ === Function.prototype) //true
原型图
constructor的作用
-
为什么Father.constructor !== Father.prototype.constructor?
function Person(area){ this.type = 'person'; this.area = area; } Person.prototype.sayArea = function(){ console.log(this.area); } var Father = function(age){ this.age = age; } Father.prototype = new Person('Beijin'); console.log(Person.prototype.constructor) //function person() console.log(Father.prototype.constructor); //function person() Father.prototype.constructor = Father; //修正 console.log(Father.prototype.constructor); //function father() var one = new Father(25); ---------------------------------------- Father.prototype.constructor = Father,这里修正了的Father的constructor。 我们知道prototype下的constructor属性返回对创建此对象的函数的引用。
- __proto__是所有对象(包括函数)都有的,它才叫做对象的原型,原型链就是靠它形成的。因此查找原型链上的属性和方法都是从__proto__查找的。
- prototype只有函数(准确地说是构造函数)才有的。它跟原型链没有关系。它的作用是:构造函数new对象的时候,告诉构造函数新创建的对象的原型是谁。
- 而Father.constructor,是从Father的原型链查找属性,也就是__proto__,因为Father继承的是Function(){},而Function(){}的constructor就是它自己
所以Father.constructor = function Function(); - 不修正的话,Father.prototype.constructor = function Person()
-
为什么需要修正Father.prototype.constructor = Father?
var man; (function(){ function Father (name) { this.name = name; } Father.prototype.sayName= function () { console.log(this.name); } man = new Father('aoyo'); })() man.sayName();//aoyo console.log(Father); //Father is not defined
上述代码中Father在闭包中,所有我们不能直接访问,当我们想对Father类增加方法时可以通过
man.constructor.prototype.sayAge = function(age){ console.log(age); } man.sayAge('20'); //20
并且如果像上面一样Father.prototype = new Person('Beijin')同时不进行修正,我们的方法将会添加到Person类,而不是Father类。
一些题目
(1)
function F() {
this.a = 1;
}
var obj = new F();
console.log(obj.prototype);//打印undefined 对象只有 __proto__属性没有prototype属性,函数才有
(2)
Object.prototype.a = 1;
var obj = {
b: 2
};
for(var i in obj) {
console.log(i); //能迭代出原型链里面的属性,所以会打印出 b和a
}
(3)
Object.prototype.a = 1;
var obj = {
b: undefined
};
console.log(obj.a);//1
console.log('b' in obj);//true //能找到处于原型链里面的bar属性
console.log(obj.hasOwnProperty('a'));//false 不是自身的属性
console.log(obj.hasOwnProperty('b'));//true 是自身的属性
(4)
function A(){
}
function B(a){
this.a = a;
}
function C(a){
if(a){
this.a = a;
}
}
A.prototype.a = 1;
B.prototype.a = 1;
C.prototype.a = 1;
//实例对象都能访问构造函数的原型对象,可以明确的是以上3个都是能拿到a的
console.log(new A().a);//1 拿到的是原型上的a=1
console.log(new B().a);//undefined this.a = a;将new B()这个实例对象的a属性这是为undefined,所以拿到的是undefined
console.log(new C(2).a);//2 将new C(2)这个实例对象的a属性这是为2,所以拿到的是2
(5)
function A () {
}
A.prototype.n = 1;
var b = new A();//b实例对象已经建立原型连接
//原型对象指向被改变,不会切断b实例对象的
A.prototype = {
n: 2,
m: 3
}
var c = new A();//c实例对象将根据新的原型建立连接
console.log(b.n, b.m); //1 undefined 这里拿到是改变prototype之前的
console.log(c.n, c.m); //2 3 这里拿到是改变prototype之后的
(6)
var F = function(){};
Object.prototype.a = function(){
console.log('a')
}
Function.prototype.b = function(){
console.log('b')
}
var f = new F();
F.a(); //打印a 对象都能访问Object.prototype中的属性和方法
F.b(); //打印b F是函数,原型链 F => F.__proto__ => Function.prototype => Function.prototype.__proto__ => Object.prototype
f.a(); //打印a 对象都能访问Object.prototype中的属性和方法
f.b(); //报错f.b is not a function 因f是F实例对象,原型链 f=>f.__proto__=>F.prototype=>F.prototype.__proto__ => Object.prototype
https://blog.csdn.net/weixin_42614080/article/details/93413476