js中的原型对象,原型链(入门级别)

当我写完博客标题的时候就有点小后悔了,这个标题好像有点大了,单单一个原型对象其实就可以扯很多了,有一个函数库 叫做 prototype.js 就是对原型对象的各种封装吧 但我仅仅也就是了解。
我以前面试过的几家公司也问过原型和作用域的问题,毕竟传统的js 实现面向对象很重要的一点就是靠原型对象来实现了,之前就一直想写一些关于这方面的东西,期间也因为其他的事情耽误了,今天就来聊一聊 菜鸟对这个的理解吧
1.原型对象
相信不了解的原型对象的小伙伴 也一定会见过 prototype 这个关键字吧,要说原型对象那么就和构造函数扯不开关系了,因为在构造函数诞生的时候 就有一个原型对象相伴而生

// 下面的Person 就是一个 构造函数
// 其实构造函数也没有那么多深层意义 就是完成 一个类实例化的一些初始化操作 
// Person 就可以看做是一个类   一般类名要大写的哦
function Person(name,age){
	this.name=name;
	this.age=age;
}
var person=new Person("zhangsan",18);// person 是Person 的一个实例化对象
console.log(person.name,person.age); // 输出  zhangsan age

然后我们顺着构造函数这条线索去找他的原型对象
上面所说的 prototype 就是指向 他的原型对象 我们 尝试着看一看长啥样哈

console.log(Person.prototype);
// 下面的就是打印的东西了
constructor: ƒ}constructor: ƒ Person(name,age)__proto__: Object

我们可以看到哈 原型对象 里面 有一个构造函数 constructor :Person 指向了它本身
后面还有一个__proto__ 这个东西 我们一会在讲解
上面看到了 原型对象中 有一个 constructor的属性 属性值 是一个和我们的构造函数同名的函数
那他俩是一个东西吗 我们在尝试打印试试看看

console.log(Person.prototype.constructor===Person); // true

看来我们猜测的是对的 就是指向了我们定义的构造函数
这里注意哈 原型对象就是 比较特殊的 普通对象 {} 只是里面有些系统给我们定义好的属性罢了
不要把它想的太复杂哈 也不要把它当做js中的一个新知识来学 都是js中基础慢慢加强封装得到的 所以说基础还是很重要的 是你是否能完成高楼大厦的根本要素

那既然是一个对象 那我们给她添加点属性 应该可以吧

Person.prototype.sex="男"; // 我给原型对象加了一个 sex的属性 属性值是 男

直接使用 Person.prototype.sex 肯定是能访问到了
但是 我不用他来访问了 上面不是还一直有一个 实例化对象吗 我用它来访问
// 我把上面的代码 再克隆一份

function Person(name,age){
	this.name=name;
	this.age=age;
}
var person=new Person("zhangsan",18);
console.log(person.sex); // undefined
Person.prototype.sex="男"
console.log(person.sex); //  男

这个就很奇怪是把 为啥上面输出undefined 下面的是 男
很关键的一点就是 我们给Person 类的原型原型对象 加上一个 sex的属性之后 他就访问到了
上面 我曾经说过的 一个 proto 说之后再将 这里 我们尝试下 打印下 person 实例化的对象他的 proto 看看长啥样子

console.log(person.__proto__);
// 下面的打印出来了 这个
{sex: "男", constructor: ƒ}
sex
:
"男"
constructor
:
ƒ Person(name,age)
__proto__
:
Object

我们看到了 sex 那个属性 这个是 Person 实例化对象的 proto_ 看起来好像我们Person类的原型对象是把
我们再去打印下 我们 构造函数的原型对象看看 是不是也长这样

console.log(Person.prototype);
{sex: "男", constructor: ƒ}
sex
:
"男"
constructor
:
ƒ Person(name,age)
__proto__
:
Object

好神奇啊 他两一模一样 不是吗 这里 我们就要论证 他们两 是不是相等了

console.log(Person.prototype===person.__proto__); // true

果不其然 他两 全等情况下 打印的是 true 那就是说两者指向的地方是相同的 
根据上面我们得到一个结论哈: 构造函数的原型对象和实例化出来子类的 proto 是相同的,
当然返货来说也行 子类的__proto__指向父类的的原型对象
不过这里还有一个疑问就是  上面的 person 对象并没有 sex 那个属性 他怎么打印出来了呢
这里附带一个注意事项: 一般不要直接覆盖掉构造函数的原型对象哈 这样很危险

Person.prototype={};
console.log(Person.prototype.constructor==Person); // 输出 false

这里终于牵扯出来了 另一个主题 就是原型链的问题
我们再把上面的代码拿过来 看看

function Person(name,age){
	this.name=name;
	this.age=age;
}
var person=new Person("zhangsan",18);
console.log(person.sex); // undefined
Person.prototype.sex="男"
console.log(person.sex); //  男

根据上面的总结来说 就是 父类的实例化对象 就是例子中的 person
打印出来的属性 sex 它本身是没有 这个属性 但是他的父亲的原型对象中有
他就会沿着 proto 去找到他的父亲 原型对象 然后打印出来这个 属性值 如果他的父亲也没有 那么他就会接着往上走 根据父亲的 proto
我们在上面不是看到 Person 构造函数 也确实有 __proto__的存在
为了满足大家的好奇心哈 我也打印下 Person的 proto

console.log(Person.prototype.__proto__)

他给我打印了下面的一大串 不过看见了一个核心的东西了 constructor
在这里插入图片描述
不就是我们的 标准数据类型之一的 Object 吗 为了验证我们的猜想哈

console.log(Person.prototype.__proto__.constructor==Object); // true

真的耶 打印出来了 true 这个说明了 Person的父亲是 Object
这样也能明白 为啥 说 OBject 是一切对向的祖先了 这里再附上一个小知识就是
null 是一切对象的 源头 因为源头就是空嘛 哈哈 起源
最后可能懵懵懂懂知道了 原型对象和原型链的概念了,
原型链: 由于逐级继承产生了一条再各个对象之间通过原型对象实现的链条,本对象找不读到的属性和方法可以沿着这个链条 往上走 直到找到为止,找不到 就输出 undefined

还有朋友 想看看 作用域和作用域链条 关注我 后面持续更新

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章