如果内容理解有误,请友友们不吝纠正
8,原型和原型链
- 1,每个
函数
都有一个prototype
,即显示原型。默认指向一个空的Object对象。【但是Object函数的显示原型不指向空对象而是null
】 - 2,每个
实例对象
都有一个__proto__
,隐式原型。【左右分别是两条下划线】 - 3,【实例对象的隐式原型的值为其对应的构造函数的显示原型的值】。【即
Fn.prototype === fn.__proto__
】 - 4,开发者可以直接操作显示原型,【ES6之前】不能直接操作隐式原型。
function Fn() {}
console.log(Fn.prototype);
var fn = new Fn();
console.log(fn.__proto__);
console.log(Fn.prototype === fn.__proto__);//true
8.1,原型
prototype
:给一类对象设置公用的属性或方法。原型就是一个技术栈。比如Array数组的所有方法,字符串的所有方法等都属于原型。原型上的方法是给实例对象使用的。
补充:
var a = "foo";
var b = new String("foo");
var c = String("foo");
console.log(a == b); //值相等就行 true
console.log(a.repeat);
console.log(typeof a);//string
console.log(typeof b);//object
console.log(typeof c);//string
console.log(a.repeat === b.repeat); //true
console.log(a === b); //一个string,一个object,false
console.log(a === c); //true
var a = '77'; // a有原型吗? 无
var b = String('77'); // b有原型吗?无 a和b都属于基本数据类型。12,[2,4] ,true ,false ,{}等,都属于js直接量,都没有原型。原型是一个技术栈。
var c = new String('77'); // c有原型吗? c有__proto__ , c没有prototype
通过String直接创建的字符串和字符串表面量为基本数据类型,属于JavaScript中的直接量(包含数字,以及数组、对象和正则表达式、数字和布尔值的直接量格式)。
通过 New String来实例化的是一个String对象, 所以可以调用String对象的方法。
8.2,原型链–本质上是隐式原型链
_proto_
: 所有数据类型都属于对象,对象的所有公用属性和方法在所有数据类型中都可以使用。即所有数据类型都链Object。
- 当通过对象访问对象的属性时,先在自身属性中寻找,找到并返回。
- 如果没有找到,会沿着隐式原型
__proto__
这条链向上查找,找到并返回。 - 若没有找到,返回undefined。表示属性已声明但并未赋值。
原型链的作用:查找对象的属性。
延申:作用域链的作用–查找变量。
-
构造函数/原型/实例对象的关系图解1:
-
构造函数/原型/实例对象的关系图解2:
所有函数的__proto__都指向Function的显示原型prototype。
因为类似Object函数都是通过 var Object = new Function() 定义的。而实例对象的隐式原型 === 构造函数的显示原型。
8.3 原型继承:通过原型链
- 构造函数的实例对象自动拥有/继承构造函数原型对象的属性和方法。【方法也是一种特别的属性。本篇文章中我将属性和方法统称为属性。】
8.4 原型链的补充:
- 每个
函数
都有一个prototype
,即显示原型。默认指向一个空的Object对象。【但是Object函数的显示原型不指向空对象而是null,是个例外
】; - 所有函数都是Function的实例。Function 是它自身的实例。即所有函数都是Function的实例,包括它本身;
- Object的原型对象是原型链的尽头。【因为
Object.prototype.__proto__
为null。】
console.log(Fn.prototype instanceof Object);//true
console.log(Function.prototype instanceof Object);//true
console.log(Object.prototype instanceof Object);//false
console.log(Function.__proto__ === Function.prototype);//true
console.log(Object.prototype.__proto__);//null
原型链的属性问题:
- 原型链是用来
查找
对象属性的。读取对象的属性值时,会自动到原型链中查找; - 设置对象的属性时,不会去查找原型链。如果当前对象中没有此属性,会直接添加此属性并赋值;
- 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上。
function Fn() {
};
Fn.prototype.a = 'xxx';
var fn1 = new Fn();
console.log(fn1.a);//xxx 读取值会先去查找对象本身,对象没有会自动到原型链去查找。就找到了原型链上的a
var fn2 = new Fn();
fn2.a = 'yyy';//设置对象属性不会去查找原型链。而是查找对象,fn2并没有a属性,就会直接添加属性并设置值。
console.log(fn1.a, fn2.a, fn2);//xxx yyy Fn{a:'yyy',__proto--:{ a:'xxx'} }
console.log(p1);// name:'Bob',age:12,__proto__
console.log(p2);//name:'Cat',age:12,__proto__
8.5 探索instanceof:
-
使用方法: a instanceof A a代表实例对象,A代表函数。
-
判断依据: A函数的显示原型对象如果在a对象的隐式原型链上,返回true。
对于:
Function instanceof Object 以及 Object instanceof Function的理解:
对于Object instanceof Object 和 Function instanceof Function的理解:
总结一下: 所有函数的显示原型对象都默认指向一个空的Object对象【Object函数除外】。 原型链的尽头是Object的隐式原型对象。对象的隐式原型对象恒等于函数的显示原型对象。 所有函数都是Function的实例,包括它本身。
关系图理解: