解析javascript–原型+原型链
写在前面
-
原型的定义:
原型(prototype)
是函数function对象的一个属性,它定义了构造函数制造出来的对象(new运算符调用的函数)的公共祖先,通过构造函数产生的对象可以继承到该原型的属性和对象,原型也是对象。 -
意念区别:
prototype
函数的原型(显示原型);__proto__
(或者[[prototype]]
)对象原型(隐式原型)。 -
constructor
:为了让构造函数构造出来的所有的对象都能找到自己的构造器。 -
原型链
的定义:在原型上再加一个原型,再加一个原型…把原型连成链,访问顺序也是按照这个链的顺序跟作用域链一样,叫做原型链。 -
本质区别:对象的原型(
__proto__
)与构造函数的原型(prototype
)属性之间性质不一样。前者是每个实例上都有的属性,后者是构造函数的属性。
晕了别着急,Following…
一、先掌握
1、浅剖析–函数中的原型对象
每个函数都有一个特殊的属性–原型(prototype)。
(1)__proto__和prototype
//创建构造函数
function Person(){};
console.log(Person.prototype);//{}
var Student=function(){};
console.log(Student.prototype);//{}

// 构造函数原型添加属性
Person.prototype.sex='female';
console.log(Person.prototype);//{ sex: 'female' }
Student.prototype.grade='2020级';
console.log(Student.prototype);//{ grade: '2020级' }

构造函数的调用方法:在正常调用函数时,在函数名的前面加上一个 new 前缀
// 调用构造函数创建实例化对象
var person=new Person();
console.log(person);//Person {}
var student=new Student();

// 给实例化对象添加属性
person.father='Person()';
console.log(person);//Person { father: 'Person()' }
student.father='Student()';
console.log(student);//Student { father: 'Student()' }

console.log(person.__proto__==Person.prototype);//true
console.log(student.__proto__==Student.prototype);//true
Attention:实例化对象的__proto__属性就是构造函数的prototype。
灵魂发问:我知道了他就是他,有什么用?
console.log(person.sex);//female
作用这不就来了:实例化对象person并没有sex属性,但是居然有打印值???
这就是原型链了:当访问person的sex属性,浏览器首先搜索person本身,没有?
浏览器继续寻找person.__proto__(person的爹爹===Person.prototype),有了!他的(Person.prototype)就是我的(person)!
还是没有咋整?假设我想要访问student.class,告诉我(student)怎么找吧~
目标:student.class
浏览器:你有class这个属性嘛?
student:不好意思,我没有~你去问问我父亲大人-->person.__proto__(Student.prototype)吧~
浏览器:他没有。。。
student:那你要不问问我祖父-->person.__proto__.__proto__(Student.prototype.__proto__===window.Object.prototype)?
浏览器:你逗我呢?他也没有!
student:那你再问问我太祖父-->person.__proto__.__proto__.__proto__(Object.prototype.__proto__),
相信我,这次肯定有结果的。
浏览器:真的栓Q!他都不在世上!
student:大哥,不好意思了,那找遍了都没有那就真没有了...
浏览器:行吧,累死人了。那我要把class属性是undefined记录了。
2、深剖析–理解原型对象
(1)创建构造函数
function Teacher(name,age,sex,wage){
this.name=name;
this.age=age;
this.sex=sex;
this.wage=wage;
}
var teacher=new Teacher('Lucky','23','female','15k');
console.log(teacher);//Teacher { name: 'Lucky', age: '23', sex: 'female', wage: '15k' }

现在看到teacher.[[prototype]].[[prototype]]里面,我(teacher)能调用里面的方法吗?比如toString(),valueOf()…
看到teacher.[[prototype]].[[prototype]].__proto__==Object
了嘛!是到顶了吗?Object.__proto__等于什么呢?是的到顶了,Object.__proto__==null
。
那Object.prototype又是什么呢?打印看看咯。
console.log(Object.prototype);//[Object: null prototype] {}
//结果如下图:有大量的方法,凡是继承自Object即可使用这些方法
console.log(Object.__proto__);//{} ƒ () { [native code] }

二、再分析

// 构造函数Foo--上溯:Object()
function Foo(name){
this.name=name;
};
console.log(Foo.prototype);//{constructor: ƒ}constructor: ƒ Foo(name)[[Prototype]]: Object
console.log(Foo.prototype.constructor);//[Function: Foo]
// 实例化对象f1,f2--上溯:Foo()
var f1=new Foo();
console.log(f1.__proto__);//{constructor: ƒ}constructor: ƒ Foo(name)[[Prototype]]: Object==Foo.prototype
console.log(f1.__proto__==Foo.prototype);//true
console.log(Foo.prototype.__proto__);//constructor: ƒ Object()
//对象
function Object(){};
console.log(Object.prototype);//constructor: ƒ Object()==Foo.prototype.__proto__
console.log(Object.prototype.constructor);//ƒ Object() { [native code] }
var o1=new Object();
console.log(o1.__proto__==Object.prototype);//true
console.log(Object.prototype.__proto__);//null
值得注意的是,Foo和Object都是通过function Function(){}创造的,所以Foo.__proto__和Object.__proto__都等于Function.prototype。万物皆对象,“食物链”的最顶端是Object,Function.prototype==Object.__proto__
三、后拓展
1、原型的增删改查
原型的增删改:不能通过实例对象修改,只能通过原型对象修改
Fruit.prototype.classify=function(){
console.log('Fruits');
}
Fruit.prototype.price='¥10';
function Fruit(name){
this.name=name;
}
var fruit=new Fruit('pear');
//添加color属性
fruit.color='green';
console.log(fruit.color);//green 给我自己添加成功了
console.log(Fruit.color);//undefined Fruit.prototype.color不存在!
// 改变price值
fruit.price='$9';//本来想改变Fruit.prototype.price=$9
console.log(fruit.price);//只是自己的fruit.price=$9
var myFruit=new Fruit('pear');
console.log(myFruit.price);//没有改变Fruit.prototype.price=¥10
// 删除颜色属性
delete fruit.price;
console.log(fruit.price);//¥10,好家伙没删除成功!
delete Fruit.prototype.price;
console.log(fruit.price);//undefined,居然成功了!
// 查找name属性和price属性
console.log(fruit.name);//查到啦!pear
console.log(fruit.price);//没有诶~,undefined
// 原型的增删改:不能通过实例对象修改,只能通过原型对象修改
2、对象的原型
对象的原型(__proto__)与构造函数的原型(prototype)属性不一样。
// 对象的原型
// 对象可以转换成给字符串
Person.prototype.name='wn';//构造函数的显式原型 Person.prototype
function Person(){
var this={
__proto__:Person.prototype
}
}
var obj={
name:'Dubi'
}
var person=new Person();
console.log(person.__proto__);//{ name: 'wn' }//实例对象的隐式原型 Person.prototype
Person.prototype=obj;
console.log(person.__proto__);//{ name: 'Dubi' }
// 实例对象的隐式原型==构造函数的显式原型
var obj1=Object.create(null);//obj1没有隐式原型,更不会继承自Object.prototype
var obj2=Object.create(obj1);
obj1.__proto__={//手动添加隐式原型
name:'lucky'
}
console.log(obj1.name);//undefined undefined没有原型,也就没有对象上的toString()方法
文章出自:https://juejin.cn/post/7118258839371628574
作者:来碗盐焗星球
原文始发于微信公众号(前端24):解析javascript–原型+原型链
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/216729.html