美文网首页js
JS原型与原型链

JS原型与原型链

作者: 书虫和泰迪熊 | 来源:发表于2020-04-02 17:20 被阅读0次

prototype(原型对象)

prototype 是函数才有的属性,只要创建一个函数,就会为该函数创建一个prototype 属性(称为原型对象)
每个原型对象(prototype) 都有两个属性:

  1. constructor 该属性指向构造函数
    Person.prototype.constructor === Person
    
  2. __ proto__
    image.png

__ proto__ (原型)

每创建一个JavaScript 对象(除了null),该对象上都会有一个 __ proto__ 属性,这个属性指向该函数的原型对象

image.png
总结公式如下
var 对象 = new 函数()
对象.__proto__  === 函数.prototype

简单描述 new 一个对象过程
正常 new一个

image.png

自己实现一个


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 只是在两个对象之间创建一个关联,这样,一个对象就可以通过委托访问另一个对象的属性和函数,所以与其叫继承,委托的说法反而更准确些

相关文章

  • 廖雪峰JS小记

    (function(){})() 原型,原型链 浅谈Js原型的理解JS 原型与原型链终极详解 对象 对象:一种无序...

  • Javascript(三)之原型继承理解

    进阶路线 3 原型继承 3.1 优秀文章 最详尽的 JS 原型与原型链终极详解 一 最详尽的 JS 原型与原型链终...

  • web前端面试之js继承与原型链(码动未来)

    web前端面试之js继承与原型链(码动未来) 3.2.1、JavaScript原型,原型链 ? 有什么特点? 每个...

  • JS原型链

    1什么是JS原型链? 通过__proto__属性将对象与原型对象进行连接. 1.1 JS原型链的作用? 组成的一个...

  • js_继承及原型链等(四)

    js_继承及原型链等(三) 1. 继承 依赖于原型链来完成的继承 发生在对象与对象之间 原型链,如下: ==原型链...

  • JavaScript 原型、原型链与原型继承

    原型,原型链与原型继承 用自己的方式理解原型,原型链和原型继承 javascript——原型与原型链 JavaSc...

  • JS的__proto__和prototype

    最近在回顾JS的原型和原型链的知识,熟悉JS的同学都知道JS的继承是靠原型链实现的,那跟原型链相关的属性__pro...

  • JS闭包问题(一)

    之前我写过一篇JavaScript原型与原型链的文章,此属于JS中的重难点。 而闭包,是JS中除了原型链之外又一个...

  • javascript中的原型链与继承

    javascript中的原型链与继承javascipt中的原型链和继承机制是这门语言所特有的,但js中的原型机制也...

  • js原型与原型链

    全局对象 window ECMAScript 规定全局对象叫做 global,但是浏览器把 window 作为全局...

网友评论

    本文标题:JS原型与原型链

    本文链接:https://www.haomeiwen.com/subject/nmhauhtx.html