最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 红宝书里的这个错误你发现了吗--对象的原型

    正文概述 掘金(路从)   2021-01-01   478

    刚刚跨了年,我在朋友圈里看到欢天喜地的景象。这个时刻我突然间想起前两天下班后,我在家翻着红宝书听着歌,翻到了高级程序设计(第4版)的第234页,那一页是这样的

    红宝书里的这个错误你发现了吗--对象的原型

    我看到这里就开始困了,可是看着看着就不困了,我把代码简化一下

        Person.prototype = {
            name:'zhaoxi'
        }
    }
    let friend = new Person()
    console.log(friend instanceof Person);  //1  true(错误)
     console.log(friend instanceof Object );  //2  true
     console.log(friend.constructor ==Person)  //3  false  (错误)
     console.log(friend.constructor ==Object)  //4  true  (错误)
    

    平平无奇的代码,红宝书上说通过 Person.prototype = { name:'zhaoxi' } 这种方式给原型添加属性,会导致 Person.prototype的原型发生变化

    所以上面的1,2,3,4,分别打印为 true true false true

    看到这里,小张的眉头皱了起来,这种方式原型会发生变化没错,一般情况化,我们会这样添加属性 Person.prototype.name = 'zhaoxi'
    但是你要是理所当然的认为 Person.prototype = { name:'zhaoxi' }和刚才是一样的,就会有很大的隐患

    所有的对象都是函数创建的

    你可能会说这样 let obj = {a:1}就不是 其实这种通过字面量创建对象的写法只是一个语法糖

    本质上,他等于let obj = new Object({a:1})

    我们验证一下

    let obj = {a:1}
    console.log(obj.__proto__==Object.prototype) //true
    console.log(obj instanceof Object)  //true
    

    数组也是一样

    let arr = [1,2,3,4]
    console.log(arr.__proto__==Array.prototype)
    console.log(arr instanceof Array)
    

    这里先不展开说,当看到这里,你可能就会明白,刚刚的两种给原型赋值的方式为何是不同的了

    是的 Person.prototype = { name:'zhaoxi' }这种方法,相当于Person的原型设置成为了新的对象,他和之前的Person.prototype已经不是一个对象创建出来的了

    那红宝书上有什么问题呢
    

    constructor(构造器)等于函数本身,指向创建他的那个函数

    说这个问题之前,我们介绍一下constructor这个小老弟

    每个函数都默认有一个propotype属性,是一个对象。这个对象默认只有一个属性constructor

    知道了这一点在回到刚开始

    let friend = new Person()
    console.log(friend.constructor ==Person)  //3  false  (错误) 应当为true
    console.log(friend.constructor ==Object)  //4  true  (错误) //应当为false
    

    就知道刚刚红宝书的判断是不正确的了

    就这就能证明?当然不

    为什么要弄这个乱七八糟的原型呢? 因为原型很重要,js的继承是基于原型实现的

    每个对象都有一个隐藏的属性——“proto”,这个属性引用了创建这个对象的函数的prototype。即:实例.proto === 原型.prototype

    我们刚刚提到,每个对象默认只有一个属性,那为何我们新建的对象 红宝书里的这个错误你发现了吗--对象的原型 除了构造器还有这么多其他的属性呢 我们可以看到这个对象的构造器(constructor)是指向Object的,因为他是有Object创建的 这些属性也是Object对象上的,之所以我们能看到并且可以使用 在这里就是因为obj.proto === Object.prototype

    这就是原型链,当对象在寻找一个属性的时候,首先会在自己本身找,找不到就会去他的原型上找,直到null 红宝书里的这个错误你发现了吗--对象的原型 就像这个,不属于obj实例的属性,只要原型上有,就可以使用,这也会产生for in之类循环不是自己想要的结果之类的副作用,以至于出现hasOwnProperty,in,Object.keys等解决方法,不过这暂时和本篇文章无关

    讲这些是因为和instanceof有关

    instanceof

    instanceof运算符的第一个变量是一个对象,暂时称为A;第二个变量一般是一个函数,暂时称为B。

    instanceof的判断队则是:沿着A的__proto__这条线来找,同时沿着B的prototype这条线来找,如果两条线能找到同一个引用,即同一个对象,那么就返回true。如果找到终点还未重合,则返回false

    就像刚刚举的那个例子 红宝书里的这个错误你发现了吗--对象的原型

    这个地方容易记错,写这篇文章之前,我问了一位未来的大佬红宝书错了吗,他说起constructor 红宝书里的这个错误你发现了吗--对象的原型 他就理解错了,constructor指向的是创建他的那个函数,而instanceof是通过原型链来判断的

    理解了这个,结合刚刚说的,我们可以解释很多看起来很奇怪的现象 红宝书里的这个错误你发现了吗--对象的原型

    一句话,js中,所有的对象都是函数创建的,所有的引用类型都是对象 ,因为他们可以从原型链中找到彼此,说起来倒有点鸡生蛋,蛋生鸡的味道

    那么,回到红宝书的剩下的两个对比

        let a = Person.prototype.constructor  //第一个构造函数是自己
        Person.prototype = {
            name:'zhaoxi'
        }
    }
    let friend = new Person()
    console.log(friend instanceof Person);  //1  true(错误)
     console.log(friend instanceof Object );  //2  true
    

    console.log(friend instanceof Person)本质上,就等于 console.log(friend.__proto__==Person.prototype),这对吗?

    这不对 还记得刚开始我们提到的吗,使用这种字面量赋值,是一种语法糖,本质上,这里的 Person.prototype = { name:'zhaoxi' }

    等于Person.prototype =new Object({ name:'zhaoxi' })

    问题就出在这里,这里的Person.prototype是由Object创建的,也就是说 friend.__proto__==Object.prototype这才是对的

    friend的隐式原型指向的不是Person.prototype,而是Person.prototype={}产生的新对象
    因为新对象是由Person.prototype new Object出来的,所以
    console.log(friend.__proto__.__proto__==Object.prototype)  //新对象的构造器指向Object  //true
    console.log(friend.__proto__.__proto__==Person.prototype)  //而不是指向Person  //false
    

    所以,应该是这样

     
      Person.prototype = {
          name:'zhaoxi'
      }
    }
    let friend = new Person()
    console.log(friend instanceof Person);  //1  false
    console.log(friend instanceof Object );  //2  true
    console.log(friend.constructor ==Person)  //3  true
    console.log(friend.constructor ==Object)  //4 false
    

    读完红宝书不是目的,读红宝书才是目的。这篇文章论证或许还有问题,希望大家多多指正

    新的2021年到了,虽然本质上看,年份只是人们用来计算时间的一种称谓,每一天都在均匀流淌没有特别之处,但大家都在期翼着新的一年会带来新的生活,或许生活总该期盼些什么才好吧


    起源地下载网 » 红宝书里的这个错误你发现了吗--对象的原型

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元