通俗易懂的理解js原型链
js的原型链
为什么需要原型链?
- 为什么需要原型:在一些场景中,比如人类行为有些要打游戏,有些要上学,有些要工作,但同时他们都需要吃饭和睡觉,但如果把每个人吃饭睡觉私有化使用的话就有点浪费内存,这时候就可以把这些每个人都需要做的行为统一拿出来放到一个公共的空间,每个人都有权限访问它,这样就可以节省内存。而实现共享的,这个时候就用到了原型 prototype。可以将附加属性附加到它,这些属性将在其构造函数的所有实例之间共享。
什么是原型链?
-
了解原型链之前先来了解一下js创建对象的过程
https://www.cnblogs.com/geekjsp/p/15807618.html -
访问一个对象时,js引擎内部的查找过程,会按以下顺序进行查找:
- 1.首先在自身的对象查找,如果有,就返回。
- 2.如果对象自身没有,就去对象所属的构造函数进行查找,如果有就返回。
- 3.如果在对象所属的构造函数中没有找到,就去构造函数的原型(链)上进行查找。
- 4.如果在整个原型链都查找完毕时,仍然找不到目标属性,就会返回undefined。
function Bar() {
this.color = "red"
}
Bar.prototype.color = "green";
let obj = new Bar();
obj.color = "blue";
console.log(obj.color); // blue
demo2:印证上述第二点:
function Bar() {
this.color = "red"
}
Bar.prototype.color = "green";
let obj = new Bar();
console.log(obj.color); // red
demo3:印证上述第三点
function Bar() {
}
Bar.prototype.color = "green";
let obj = new Bar();
console.log(obj.color); // green
demo4:印证上述第四点
function Bar() {
}
let obj = new Bar();
console.log(obj.color); // undefined
prototype和[[prototype]]有什么关系?
其实[[prototype]]和__proto__意义相同,均表示对象的内部属性,其值指向对象原型。前者在一些书籍、规范中表示一个对象的原型属性,后者则是在浏览器实现中指向对象原型。
prototype是函数才有的属性,Object没有
原型链过程
请看下面的代码片段:
function Person(){}
Person.__proto__==Function.prototype //true
let a={}
a.__proto__==Object.prototype //true
let Teacher=new Person();
Teacher.__proto__==Person.prototype //true
--------------------------------------------------------
function test99(){}
test99.__proto__==Object.prototype
//true
test99.__proto__==Function.__proto__
//false
---------------------------------------------------------
var one = {x: 1};
var two = new Object();
one.__proto__ === Object.prototype // true
two.__proto__ === Object.prototype // true
one.toString === one.__proto__.toString // true
说明 one.就是在one.__proto__.查找
---------------------------------------------------------
let objP = function() {};
let obj = new objP();
创建一个obj对象 把obj对象的__proto__指向prototype
对象的__proto__属性是创建对象时自动添加的,默认值为其构造函数的prototype
因此:
objP.prototype.sayHell=function(str){console.log(str)}
let obj = new objP();
obj.__proto__ //{sayHell: ƒ, constructor: ƒ}
obj.sayHell('搞懂js原型链')
obj.方法名的时候会到__proto__上找因此会到objP.prototype
--------------------------------------------------------
function test666(){}
let test7=new test666()
test7.__proto__===test666.prototype
//true
test7.__proto__.__proto__===test666.prototype.__proto__
//true
test666.prototype.__proto__==Object.prototype
//true
Object.__proto__.__proto__
//{constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …}
Object.__proto__.__proto__.__proto__
//null
--------------------------------------------------------
var fn =function (){};
prototype是在定义函数时自动添加的, 默认值是一个空Object对象
fn.prototype
// {constructor: ƒ}
// constructor: ƒ Person()
// [[Prototype]]: Object
可以添加属性和方法,这些属性和方法将在其构造函数的所有实例之间共享
fn.prototype.name='wen';
fn.prototype.age='18';
var obj1=new fn();
var obj2=new fn();
console.log(obj1.name);
console.log(obj2.age);
obj1.constructor.prototype==fn.prototype
obj1.name的查找过程:
obj1> 构造函数fn > fn.__proto__>fn.__proto__.__proto__>null 返回undefined
--------------------------------------------------------
原型链总结
-
大多数情况下,__proto__可以理解为“构造函数的prototype”。
-
每当您在 JavaScript 中访问对象的属性时,它首先会检查该属性是否在对象内部可用。如果不是,它检查它的原型对象。如果有返回。否则,它将检查该属性是否存在于原型的原型中,如果不存在则再次检查该属性是否存在于原型的原型中,依此类推。
那么它会以这种方式检查多长时间?__proto__如果在任何点找到该属性或在任何点的值为null或,它将停止undefined。然后它会抛出一个错误,通知你它无法找到你正在寻找的属性。(https://www.freecodecamp.org/news/all-you-need-to-know-to-understand-javascripts-prototype-a2bff2d28f03/)
console.log(Object.prototype.proto===null);//true