JS中原型、原型链的理解
1.构造函数
构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。构造函数模式中拥有了类和实例的概念,并且实例和实例之间是相互独立的,即实例识别。构造函数就是一个普通的函数,创建方式和普通函数没有区别,不同的是构造函数习惯上首字母大写。
另外就是调用方式的不同,普通函数是直接调用,而构造函数需要使用new关键字来调用。
function Person(name, age, gender) { //创建一个构造函数 this.name = name this.age = age this.gender = gender this.sayName = function () { //定义构造函数中的一个方法 alert(this.name); } } var per = new Person("孙悟空", 18, "男"); //调用创建的构造函数,必须用new关键字调用 console.log(per) //当我们直接在页面中打印一个对象时,事件上是输出的对象的toString()方法的返回值 //toSting(): 可以把一个Number转换为字符串
每创建一个Person构造函数,在Person构造函数中,为每一个对象都添加了一个sayName方法,也就是说构造函数每执行一次就会创建一个新的sayName方法。这样就导致了构造函数执行一次就会创建一个新的方法,执行10000次就会创建10000个新的方法,而10000个方法都是一摸一样的,为什么不把这个方法单独放到一个地方,并让所有的实例都可以访问到呢?这就需要原型(prototype)
2.原型对象
原型对象就相当于一个公共的区域,所有同一个类的实例都可以访问到这个原型对象,我们可以将对象中共有的内容,统一设置到原型对象中在JavaScript中。每当定义一个函数数据类型(普通函数、类)时候,都会天生自带一个prototype属性,这个属性指向函数的原型对象,并且这个属性是一个对象数据类型的值。
在JavaScript中是使用构造函数来新建一个对象的,每一个构造函数的内部都有一个 prototype 属性,它的属性值是一个对象,这个对象包含了可以由该构造函数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,在这个对象的内部将包含一个指针,这个指针指向构造函数的 prototype 属性对应的值,在 ES5 中这个指针被称为对象的原型。一般来说不应该能够获取到这个值的,但是现在浏览器中实现了 __proto__属性来访问这个属性,但是最好不要使用这个属性,因为它不是规范中规定的。ES5 中新增了一个 Object.getPrototypeOf() 方法,可以通过这个方法来获取对象的原型。
3.原型链
3.1 .__proto__和constructor
每一个对象数据类型(普通的对象、实例、prototype......)也天生自带一个属性__proto__,属性值是当前实例所属类的原型(prototype)。原型对象中有一个属性constructor, 它指向函数对象。
function Person() {} var person = new Person() console.log(person.__proto__ === Person.prototype)//true console.log(Person.prototype.constructor===Person)//true //顺便学习一个ES5的方法,可以获得对象的原型 console.log(Object.getPrototypeOf(person) === Person.prototype) // true
3.2 何为原型链?
在JavaScript中万物都是对象,对象和对象之间也有关系,并不是孤立存在的。对象之间的继承关系,在JavaScript中是通过prototype对象指向父类对象,直到指向Object对象为止(person → Person → Object),这样就形成了一个原型指向的链条,专业术语称之为原型链
当我们访问对象的一个属性或方法时,它会先在对象自身中寻找,如果有则直接使用,如果没有则会去原型对象中寻找,如果找到则直接使用。如果没有则去原型的原型中寻找,直到找到Object对象的原型,Object对象的原型没有原型,如果在Object原型中依然没有找到,则返回undefined。注意:Object对象是老祖宗,没人比他更大了,所以Object的_proto_为空, 即原型链的尽头一般来说都是 Object.prototype
console.log(Object.prototype.__proto__ === null) // true
我们可以使用对象的hasOwnProperty()
来检查对象自身中是否含有该属性;使用in
检查对象中是否含有某个属性时,如果对象中没有但是原型中有,也会返回true
function Person() {} //创建构造函数 Person.prototype.a = 123; //给构造函数的原型实例中添加a属性,而不是在构造函数中添加a属性 Person.prototype.sayHello = function () { //给构造函数的原型实例中添加sayHello方法,而不是在构造函数中添加该方法 alert("hello"); }; var person = new Person() //创建一个构造函数实例对象 console.log(person.a)//123 // 虽然在构造函数中没有a属性,但是在其父函数(实例原型)中有该属性,所以构造 函数继承了a属性,仍能正常输出而不报错 console.log(person.hasOwnProperty('a'));//false // hasOwnProperty方法仅检查对象自身是否含有某属性,a属性是继承的,自身中没 有,所以不能正常输出 console.log('a'in person)//true // 若当前实例对象的构造函数中没有属性a时,in方法可以查询其父函数或祖父函数中 是否有a属性,即查户口查到祖宗十八代去了,23333 //getPrototypeOf():返回参数内部特性Prototype的值 console.log(Object.getPrototypeOf(person1) == Person.prototype) //true
4.原型链指向
p.__proto__ // Person.prototype Person.prototype.__proto__ // Object.prototype p.__proto__.__proto__ //Object.prototype p.__proto__.constructor.prototype.__proto__ // Object.prototype Person.prototype.constructor.prototype.__proto__ // Object.prototype p1.__proto__.constructor // Person Person.prototype.constructor // Person
5.如何获取对象中非原型链上的属性?
使用后hasOwnProperty()
方法来判断属性是否属于原型链的属性
function iterate(obj){ var res=[]; for(var key in obj){ if(obj.hasOwnProperty(key)) res.push(key+': '+obj[key]); } return res; }
function关键词本身也有一个原型对象”Function”,其他函数在使用“function”关键词时,一定存在属性继承于原型对象“Function.prototype”
原型的作用
假如没有原型,那我们需要这样声明一个对象
var obj = { toString: window.Object.prototype.toString, hasOwnPropertyOf: window.Object....... } obj.toString() var obj2 = { toString: window.Object.prototype.toString, hasOwnPropertyOf: window.Object....... } obj2.toString()
有了原型,我们只需要一句话就可以搞定了
let obj = {}
所以原型的作用就是让你无需重复声明共有属性,省代码,省内存。
来源 | https://blog.csdn.net/qq_38867012/article/details/124001609
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通