当前位置: 首页 > Web前端 > JavaScript

【深入02】原型链

时间:2023-03-26 22:15:25 JavaScript

导航2021/07/21更新2021/07/22更新【【深入01】执行上下文】(https://juejin.im/post/684490...[[深入02]原型链](https://juejin.im/post/684490...[[深度03]继承](https://juejin.im/post/684490...[[深度04]EventCycle](https://juejin.im/post/684490...[[深入05]Curried偏函数记忆](https://juejin.im/post/684490...[[In-深度06]隐式转换与运算符](https://juejin.im/post/684490...[[深入07]浏览器缓存机制(http缓存机制)](https://juejin.im/post/684490...[[深入08]前端安全](https://juejin.im/post/684490...[[深入09]深浅复制](https://juejin.im/post/684490...im/post/684490...[[深入10]DebounceThrottle](https://juejin.im/post/684490...[[深入11]前端路由](https://juejin.im/post/684490...[[深入12]前端模块化](https://juejin.im/post/684490...[[深入13]观察者模式发布订阅模式二-way数据绑定](https://juejin.im/post/684490...[[深入14]canvas](https://juejin.im/post/684490...[[深入15]webSocket](https://juejin.im/post/684490...[[深入16]webpack](https://juejin.im/post/684490...[[深入17]http和https](https://juejin.im/post/684490...://juejin.im/post/684490...【【深入18】CSS-interview](https://juejin.im/post/684490...[[深入19]手写承诺](https://juejin.im/post/684490...[[深入20]]手写函数](https://juejin.im/post/684490...[[react]Hooks](https://juejin.im/post/684490...[[部署01]Nginx](https://juejin.im/post/684490...[[部署02]Docker部署vue项目](https://juejin.im/post/684490...[[部署03]gitlab-CI](https://juejin.im/post/684490...[[源码-webpack01-pre-知识]AST抽象语法树](https://juejin.im/post/684490...[[源码-webpack02-pre-知识】Tapable](https://juejin.im/post/684490...[[源码-webpack03]手写webpack-compiler简单编译过程](https://juejin.im/post/684490...[[源码]ReduxReact-Redux01](https://juejin.im/post/684490...[[源码]axios](https://juejin.im/post/684490...[[源码]vuex](https://juejin.im/post/684490...[[源码-vue01]数据响应及初始化渲染](https://juejin.im/post/684490...构造器生成实例对象的缺点,属性和方法都是在实例上生成的,属性和方法不能在多个实例间共享。javaScript继承机制的设计思想:原型对象的所有属性和方法都可以被实例对象共享。所有函数都有原型属性。指向一个对象对于构造函数:当构造函数生成一个实例时,构造函数的prototype属性会成为实例对象的原型。原型对象上的属性不是实例对象本身的属性。只要修改了原型对象,修改就会立即反映到所有的实例对象上。实例对象和原型对象怎么会有同名的属性和方法,实例对象在读取这个属性的时候,会读取自己的属性,而不是原型上的属性。原型对象的作用:定义所有实例共享的属性和方法成为其他对象的原型,原型对象也是对象,也有自己的原型,一层层形成链条,最终会被追溯回到Object.prototype,也就是Object构造函数的prototype属性,也就是所有的对象都继承了Object.prototype对象的属性和方法,这也是为什么所有的对象都有valueOf和toString的原因。Object.prototype的原型为null。Null没有属性和方法,也没有自己的原型。原型链以null结尾,防止死链覆盖覆盖读取涉及到对象的属性时,如果自身和原型上存在同名的属性和方法,则优先读取自身的属性。这称为覆盖。,一直到Object.prototype,上一层还是没有返回undefined,在整个原型链上找某个属性,对性能有影响重写:重写的意思是functionA(){}//--------------------定义构造函数AA.prototype=newArray()//----------将A.prototype指向实例数组,则A的实例可以继承数组原型链上的属性和方法A.prototype.constructor=A//--------修改原型同时也要修改构造函数,防止意外consta=newA()a.push(1)ainstanceofArray//trueconstructorprototype对象有一个constructor属性,它指向prototype属性所在的构造函数因为constructor属性默认位于原型对象上,所以constructor属性被所有实例继承。作用:(1)构造函数的作用是知道是哪个构造函数生成了一个实例对象。(2)构造函数的另一个作用:一个实例可以用来创建另一个实例注:constructor表示原型对象和构造函数之间的关系。如果修改了原型对象,一般会同时修改constructor属性,防止引用时出错,=>因为修改了原型后,A.prototype.构造函数不再指向A,而是新分配给原型对象的对象所指向的构造函数修改原型对象也必须修改构造函数,以防止引用错误!!!!!!!nameattributeconstructor.name=>构造器名称constructorconstructor表示原型对象和构造函数的关系,修改原型需要修改构造函数同时防止引用错误instanceof返回一个布尔值,表示对象是否为构造函数instanceof的实例左边是Instance对象,右边是构造函数instanceof会检查右边构造函数的原型对象prototype,是否在左边对象的原型链上由于instanceof检查整个原型链,所以同一个实例对象可能为多个构造函数返回true。有一种特殊情况:如果左边对象的原型链中只有null(即左边对象的原型对象为null),那么instanceof的判断就会被扭曲instanceof的用途之一就是判断值类型,(但只能用来判断对象,不能判断值的原始类型)。对于undefined和null,instanceOf操作符总是返回false使用instanceof可以巧妙解决,调用构造函数时忘记添加新命令的问题instanceofffunctionA(){}consta=newA()console.log(ainstanceofA,'instanceof的原理是检查右构造函数的原型对象是否在左对象的原型链上')console.log(A.prototype.isPrototypeOf(a),'instanceof等价于这个')vard=newDate();dinstanceofDate//true//d是Date的一个实例,也是Object的一个实例dinstanceofObject//true//因为instanceof会检查右边构造函数的实例,是否在该构造函数的原型链上leftinstanceobject,checkstheentireprototypechain//所以同一个实例可能有多个构造函数函数返回turevarobj=Object.create(null);//创建一个以null为原型对象的实例typeofobj//"object"Object.create(null)instanceofObject//falseinstallof可以解决调用构造函数A()时忘记添加新命令的情况{if(!(thisinstanceofA)){//如果this不是A的实例,表示不是new命令调用,然后执行newreturnnewA()}else{this.name='woow_wu7'}}consta=newA()console.log(a)Object.getPrototypeOf返回原型对象参数对象Object.getPrototypeOf是获取原型对象的标准方法注意:参数是一个对象,也可以是一个函数,因为函数也是一个对象,继承类在es6中可以判断,Object.getPrototypeOf(ColorPoint)===Point//true,ColorPoint是一个类,也就是一个获取参数对象原型对象的函数,这是标准方法获取原型对象Object.getPrototypeOf(Object.prototype)===null//trueObject.getPrototypeOf(Function.prototype)===Object.prototype//trueObject.getPrototypeOf({})===Object.prototype//true将第一个参数对象的原型设置为第二个参数对象Object.setPrototypeOf(existingobject,prototypeobject)returnsValue:返回第一个参数对象参数:The第一个参数是已有对象,第二个参数是原型对象consta={}constb={name:'woow_wu7'}constres=Object.setPrototypeOf(a,b)//设置b为a的原型,注意返回值为aObject.getPrototypeOf(a)===b//trueconsole.log(a.name)console.log(res)//a,返回值为anew命令可以用Object.setPrototypeOfvar模拟F=乐趣ction(){this.foo='bar';};varf=newF();//等同于varf=Object.setPrototypeOf({},F.prototype);//返回值f是第一个Parameter{}//Object.setPrototypeOf({},F.prototype)=>等同于{}.__proto__=F.prototypeF.call(f);object.create通过new命令生成一个实例对象执行constructor(constructor其实就是一个普通的函数,但是用new命令调用的时候this指向实例,首字母大写区分,不大写也可以,不过是约定俗成)由一个对象生成,有时只能获取到一个对象,要生成实例对象Object.create,实例完全继承原型对象的属性和方法Object.create()以参数对象为原型返回一个实例对象,实例完全继承原型对象的属性和方法原型对象手动实现AnObject.createObject._create=function(obj){functionF(){}F.prototype=obj//创建一个新的构造函数,将构造函数的原型指向传入的对象,执行构造函数,即实例的原型指向传递的对象returnnewF()}如果想生成一个不继承任何属性和方法的对象,可以使用Object.create(null)如果Object.create()的参数为空,或者不是对象,会报错Object.prototype.isPrototypeOf实例对象的isPrototypeOf属性用于判断对象是否为参数obje的原型ctObject.prototype.__proto__实例对象的原型对象,根据语言标准Deploy__proto__,只有浏览器需要,其他环境没有__proto__属性。不推荐使用__proto__。而是使用标准的Object.getPrototypeOf来读取原型,并使用Object.setPrototypeOf(现有对象,原型对象)来设置原型。原型对象获取方法比较-`obj.__proto__`//仅浏览器可用,不推荐使用-obj.constructor.prototype//手动修改原型时,可能会变形-Object.getPrototypeOf()//推荐直接修改原型对象的方法,需要修改构造函数防止失真functionA(){}consta=newA()functionB(){}B.prototype=aconstb=newB()b.constructor.prototype===a//false//因为:b.constructor===a.constructor===A.prototype.constructor===A//所以:b.constructor.prototype===A.prototype//结论:直接修改prototype属性时,一定要修改constructor属性!!!!!!!!!!!!!!!!!!(重要)//如果是这样:functionA(){}consta=newA()functionB(){}B.prototype=aB.prototype.constructor=B//修改原型,修改构造函数同时那么引用就不会出错constb=newB()b.constructor.prototype===a//trueObject.prototype.hasOwnProperty返回一个布尔值,表示是否是对象本身的属性,不包括原型链上的属性Date。hasOwnProperty('length')//trueDate.hasOwnProperty('toString')//falsein运算符in运算符返回一个布尔值,表示该属性是否存在于对象中,无论是自身属性还是继承属性注意:in运算符不区分自身属性和继承属性例子:functionX(){}X.prototype.name='woow_wu7';letx=newX()'name'inX//true//因为:in运算符返回一个布尔值,表示该属性是否存在于对象中,不管是自身的还是继承的//所以:'name'inX=>returnstrueforinandforofforin可以遍历对象和数组forof数组只能遍历数组,i表示:key用于对象,i表示:当key用于对象时,for...in会遍历自身的属性和继承的属性,forof用于数组:i表示valueconstobjP={sex:'man'}constobj={name:'woow_wu7',age:20,address:'hangzhou'};Object.setPrototypeOf(obj,objP)for(letiinobj){console.log(i,'forinloop=>forobjects,willtr??averseitselfandinheritedproperties')//name,age,address,sexif(obj.hasOwnProperty(i)){console.log(i,'如果只想遍历自身属性,可以用Object.prototype.hanOwnProperty(属性名)来过滤')//姓名,年龄,地址}}我的简书:https://www.jianshu.com/p/1a2...constructorconstructor代表structure函数和原型对象之间的关系。如果修改了原型对象,需要同时修改构造函数,防止引用错误——(每个构造函数都有一个原型属性,原型的构造函数指向原型所在的构造函数)instanceof的原理:instanceof检查是否(右边构造函数的prototype属性)在(左边对象)instanceof的原型链上无效:如果一个对象的__proto__属性指向null,instanceof会失败,因为右边构造函数的原型=>终点是Object.prototype,是否在左边对象的原型链上Object.prototype.__prototo__===nullObject.prototypeinstanceofOjbect//false//Object.create(null)instanceofObject//false,因为创建的实例没有任何属性和方法,也没有原型2021/07/24更新null没有任何属性和方法如何生成没有任何属性和方法的对象Object.create(null)如何模拟一个Object.create在修改prototype属性时,必须同时修改constructor属性,防止引用错误,否则会指向被赋值对象的构造函数原型上的constructor