1。我们知道,在面向对象编程的语言中,有一句统筹全局的中心语句——“一切皆对象”,原型和原型链也是基于这个基本认识。在学习js的继承机制——“原型”和“原型链”这两个概念的理论时,总是忘乎所以,忘乎所以。所以死记硬背真的没什么用,你要深入理解背后的设计思想,还要理解和背诵,无异于给老虎插上翅膀。至于为什么这么说,就跟着这篇文章揭开Jenny的面纱,像剥洋葱一样探寻它的本质吧。来不及解释,上车。2.JS继承的设计思想我们知道创建对象有两种方式:一种是最常见的对象字面量,另一种就是常说的通过new创建对象实例。其实这两种方式描述的对象是等价的,属性和方法是一致的。//文字对象letobj={name:"yichuan",age:18,sayName(){console.log("name:",this.name);}}//new创建对象实例letobj2=newObject();obj2.name="pingping";obj2.sayName=function(){console.log("name:",this.name);}使用对象字面量或Object构造函数可以很容易地创建,但是当创建多个对象具有相同接口时,会重复很多代码。那么,我们想能不能创建一个容器,把共享的属性和方法存储在里面,让它们可以在多个对象中使用。在es6之前,并没有对类和继承结构的正式支持,但是可以通过原型链继承来模仿类和继承。事实上,es6classes确实是封装了构造函数和原型继承的语法糖。工厂模式工厂模式可以抽象出创建具体对象的过程,解决创建多个相似对象的问题,但是没有解决对象的识别问题,不能设置新创建对象的类型。//工厂模式functioncreatePerson(name,age,city){letobj=newObject();obj.name=名称;obj.age=年龄;obj.city=城市;obj.sayName=function(){控制台。log("我的名字是:",this.name);}returnobj;}letpreson1=createPerson("yichuan",18,"BeiJing");letpreson2=createPerson("onechuan",28,"GuangZhou");js中的构造函数模式用于创建特定类型的对象.Objectnativeconstructor用于创建一个对象,在运行时可以直接在执行环境中使用。但实际上,我们也可以定义自定义构造函数,以函数的形式为自己的对象定义属性和方法。//构造函数模式函数Person(name,age,city){this.name=name;这个。年龄=年龄;这个。城市=城市;this.sayName=function(){console.log(this.name);}}letp1=newPerson("yichuan",18,"Beijing")letp2=newPerson("onechuan",19,"Guangzhou")p1.sayName()//yichuanp2.sayName()//onechuan建设与工厂模式相比,函数模式没有显式创建对象,属性和方法直接赋值给this,没有return返回任何值。那么使用new构造函数创建一个对象,具体会发生什么呢?会有以下操作:1)在内存中开辟新空间,创建新对象。2)这个新对象中的_proto_属性被赋予了构造函数的prototype属性。3)构造函数中的this指向新对象。4)为新对象添加属性。5)如果构造函数返回一个非空对象,返回那个对象;否则,返回刚刚创建的新对象。什么是构造函数?其实构造函数也是一个函数,它和普通的函数没有什么区别,只是调用方式不同而已。new调用的函数是一个构造函数。构造函数定义的方法会在每个实例上创建,每定义一个函数,就会初始化一个对象。功能人(姓名,年龄,城市){this.name=name;这个。年龄=年龄;这个。城市=城市;this.sayName=newFunction("console.log(this.name);");}Prototype模式的每个函数都会创建一个原型属性,它是一个包含属性和方法的对象,这些属性和方法应该被一个实例共享具体的引用类型,而这个对象就是调用构造函数创建的实例对象的原型,那么这个对象就称为原型对象。原型对象的作用是:原型对象上定义的属性和方法可以被对象实例共享,即对象原型相当于一个容器,用于存放公共的属性和方法。等等,这不就是前面说的构造函数中直接赋值给对象实例的值吗?其实不是的,在定义构造函数Person的时候,构造函数内部是一个没有任何属性和方法的空对象。但是,可以通过直接在Person的原型上定义属性和方法来附加到Person对象的原型。这样通过newPerson()得到的对象实例就可以共享Person.prototype上的属性和方法了。如下:functionPerson(){}Person.prototype.name="宜川";Person.prototype.age=18;Person.prototype.city="北京";Person.prototype.sayName=function(){console.log(this.name);}letp1=newPerson();p1.sayName();letp2=newPerson();p2.sayName();3.在原型和原型链上面的原型模式中,已经引入了原型和原型对象的概念,那么我们重新梳理一下思路:构造函数的prototype属性所指向的原型对象定义了可以共享的属性和方法所有实例对象,不需要共享的属性和方法直接在构造函数上定义。通过构造函数创建的实例对象将自动具有原型对象上共享的属性或方法。functionPerson(name){this.name=name;}Person.prototype.address="earth";constp=newPerson("yichuan");//{name:age}constp1=newPerson("onechuan");在上面的代码中,一个公共属性Person.prototype.address="earth";定义在构造函数Person的原型上,那么通过new生成的实例对象p和p1自然会继承属性address,而p和p1各自的name值分别是“yichuan”和“onechuan”。函数与对象的关系函数是对象,对象是通过函数创建的。函数和对象不仅仅是包含和被包含的原型的类别。显式原型:prototype,是每个函数的唯一属性隐式原型:_proto_,是每个对象所具有的属性原型和原型链原型。一个函数可以看作一个类,原型是所有类都具有的属性。统一的方法。原型链:每个对象都有一个_proto_,指向它的prototype原型对象;它的prototype原型对象还有一个_proto_,指向它的prototype原型对象,所以查找prototype直到顶层对象Object.prototype,最终指向null。用一张图描述一下原型链:我们看到原型链的最终归属是一个对象,Object.prototype的_proto_指向null,这样设置是为了避免死循环,所以一切都是空的。4.参考文章【重点】图解:告诉面试官什么是JS原型和原型链?不面试就得了解原型和原型链《Javascript高级程序设计》5。最后写的所有实例对象的_proto_都指向构造函数的prototype原型对象(即:p._proto_===Person.prototype)。所有的函数(包括构造函数)都是Function的实例,所有函数的_proto_都指向Function的原型对象。所有原型对象(包括Function的原型对象)都是Object的实例,所以_proto_指向Object(构造函数)的原型对象。而Object构造函数的_proto_指向null。Function构造函数本身是Function的实例,所以_proto_指向Function的原型对象。
