prototype(原型对象)
prototype 是函数才有的属性,只要创建一个函数,就会为该函数创建一个prototype 属性(称为原型对象)
每个原型对象(prototype) 都有两个属性:
- constructor 该属性指向构造函数
Person.prototype.constructor === Person
- __ proto__
image.png
__ proto__ (原型)
每创建一个JavaScript 对象(除了null),该对象上都会有一个 __ proto__ 属性,这个属性指向该函数的原型对象
总结公式如下
var 对象 = new 函数()
对象.__proto__ === 函数.prototype
简单描述 new 一个对象过程
正常 new一个
自己实现一个
image.png
原型链
上面已经说了
p.__proto__ === Person.prototype // true
同样 Person.prototype 也是一个对象,所以他也有 __ proto__ 属性,所以
Person.prototype.__proto__ === Object.prototype // true
Object也有__ proto__ 属性,但是比较特殊是null,说明 Object 没有继承
Object.Prototype.__proto__ === null // true
所以有
p.__proto__.__proto__ === Object.prototype // true
p.__proto__.__proto__.__proto__ === null // true
我们把这种由 __ proto__ 串起来直到 Object.prototype.__ proto__ 为 null 的链叫原型链,原型链的形成真正靠的是 __ proto__,而不是 prototype。
如下图
image.png
由此可以得到下面结论
所有函数都是 Function 的实例,Object, Number, String 这些都是函数 - 构造函数,所以他们都是Function 的实例。
Number.__proto__ === Function.prototype // true
String.__proto__ === Function.prototype // true
Object.__proto__ === Function.prototype // true
那Function是谁的实例?
Function的直接实例还是Function
Function.__proto__ === Function.prototype // true
Function.__proto__.__proto__ === Function.prototype.__proto__ // true
instanceof的底层实现原理,手动实现一个instanceof
instanceof 运算符用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上
即 实例.__ proto __ ==? 函数.prototype 或者沿着原型链想上(Object)寻找,如下
实例.__ proto __ . __ proto __ ....... ==? 函数.prototype
// 因为 instanceof 是个关键字,我们只能写一个函数 instance_of 来模拟 instanceof 功能
function instance_of(L, R) { //L 表示左表达式,R 表示右表达式
var O = R.prototype;
L = L.__proto__;
while (true) {
if (L === null)
return false;
if (O === L) // 这里重点:当 O 严格等于 L 时,返回true
return true;
L = L.__proto__;
}
}
// 测试
var a = []
var b = {}
function Foo(){}
var c = new Foo()
function child(){}
function father(){}
child.prototype = new father()
var d = new child()
console.log(instance_of(a, Array)) // true
console.log(instance_of(b, Object)) // true
console.log(instance_of(b, Array)) // false
console.log(instance_of(a, Object)) // true
console.log(instance_of(c, Foo)) // true
console.log(instance_of(d, child)) // true
问题:A instanceof B 和 B.isPrototypeOf(A) 区别
· A instanceof B :instanceOf运算符用于检测 构造函数(B)的prototype属性是否出现在某个实例对象(A)的原型链上。
· B.isPrototypeOf(A):检测B对象是否出现于A对象的原型链上
注:isPrototypeOf()
与 instanceof
运算符不同。在表达式 "object instanceof AFunction
"中,object
的原型链是针对 AFunction.prototype
进行检查的,而不是针对 AFunction
本身。
若使用 isPrototypeOf 检测出来的结果为 true 则 instanceof 一定为true,反之不成立。
小练1:
function Person() {
}
Person.prototype.name = 'Kevin';
var person = new Person();
person.name = 'Daisy';
console.log(person.name) // Daisy
delete person.name;
console.log(person.name) // Kevin
第一次输出 person.name 自然是 Daisy,但是当我们删除了 person.name 之后,在person对象中读取不到 name 属性,就会从person的原型 person.__ proto__ 中读取,即从 Person.prototype 中读取name。则为 Kevin。
继承
原型链是实现继承的一种方式
String, Number 继承 Object
String.prototype.__proto__ === Object.prototype // true
Number.prototype.__proto__ === Object.prototype // true
Object 没有继承
Object.prototype.__proto__ === null
Function继承谁呢?哈哈!!Function.prototype 也是一个对象,所以Function继承Object~~
Function.prototype.__proto__ === Object.prototype
小练2:
var F = function() {}
Object.prototype.a = function() {}
Function.prototype.b = function() {}
var f = new F()
问:f.a 和 f.b 那个能拿到???
答:f.a 能拿到,f.b 不能拿到
解析:f.a 先去 f 对象中查找 a 发现没有,再去 f.__ proto__中查找 a,即是F.prototype 中查找 a,又没有,F.prototype是对象再接着去 F.prototype的原型,即F.prototype.__ proto__ 上查找,即Object.prototype 上查找,lucky 找到
补充
constructor
function Person() {
}
var person = new Person();
console.log(person.constructor === Person); // true
当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取,正好原型中有该属性,所以:
person.constructor === Person.prototype.constructor
__ proto__
其次是 __ proto__ ,绝大部分浏览器都支持这个非标准的方法访问原型,然而它并不存在于 Person.prototype 中,实际上,它是来自于 Object.prototype ,与其说是一个属性,不如说是一个 getter/setter,当使用 obj.__proto __ 时,可以理解成返回了 Object.getPrototypeOf(obj)。
真的是继承吗?
最后是关于继承,前面我们讲到“每一个对象都会从原型‘继承’属性”,实际上,继承是一个十分具有迷惑性的说法,引用《你不知道的JavaScript》中的话,就是:
继承意味着复制操作,然而 JavaScript 默认并不会复制对象的属性,相反,JavaScript 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些
网友评论