Javascript 构造函数、原型对象、实例之间的关系
# Javascript 构造函数、原型对象、实例之间的关系 # 创建对象的方式 # 1.new object() 缺点:创建多个对象困难 var hero = new Object(); // 空对象 hero.blood = 100; hero.name = '刘备'; hero.weapon = '剑'; hero.attack = function () { console.log(this.weapon + ' 攻击敌人'); } # 2.对象字面量 缺点:创建多个对象困难 var hero = { blood: 100, name: '刘备', weapon: '剑', attack: function () { console.log(this.weapon + ' 攻击敌人'); } } # 3.工厂函数 创建多个对象 缺点:无法获取具体类型(typeof 返回结果是Object) function createHero(name, blood, weapon) { var o = new Object(); o.name = name; o.blood = blood; o.weapon = weapon; o.attack = function () { console.log(this.weapon + ' 攻击敌人'); } } hero = createHero('刘备', 100, '剑') # 4.通过构造函数来实现 解决了工厂对象遗留的问题 function Hero(name, blood, weapon) { this.name = name; this.blood = blood; this.weapon = weapon; this.attack = function () { console.log(this.weapon + ' 攻击敌人'); } } var hero1 = new Hero('刘备', 100, '剑'); var hero2 = new Hero('关羽', 100, '刀'); console.log(hero1.constructor === Hero); # 而constructor可以改变,所以不建议这么用 console.log(hero1 instanceof Hero); # 这样看它是否是Hero的对象 console.log(hero1.attack === hero2.attack); # ===比较地址。这里返回False # 问题一:new Hero具体干了啥? # .首先会在内存中创建一个空对象 # ..设置构造函数的this,让this指向刚刚创建好的对象 # ...执行构造函数中的代码 # ....返回对象 # 问题二:为什么attack函数不是同一个,却又能通过this去访问实例属性? # new的时候会执行构造函数中的代码,也就是会执行function ()的时候会创建自己的一个空this对象,所以Hero不同实例的attack其实不是同一个。 # 而调用的时候是通过hero1.attack()和hero2.attack()调用的,这时候this代表的是hero1\hero2,所以能通过this.weapon来调用。 # 问题三:如果需要通过Hero构造函数构造几十上百个对象,那么attack方法不是会浪费很大的资源? # 解决方案一:将attack声明为全局的,在Hero构造的时候赋值给this.attack。这样的弊端是,当构造方法一多的时候,方法名容易重名。 # 解决方案二:通过构造函数的原型对象去实现。 # 每一个构造函数都有一个属性prototype,也就是原型对象。通过同一个构造函数new出来的实例共享一个原型对象中的属性。 function Student(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } Student.prototype.sayHi = function () { console.log('大家好,我是' + this.name) } var s1 = new Student('lilei', 18, '男'); var s1 = new Student('hmm', 18, '女'); s1.sayHi();s2.sayHi(); # 如果原型对象和构造函数中都有sayHi方法的话,优先调用构造函数中的sayHi方法。 # Student构造函数、Student原型对象、Student实例/对象之间的关系 # 1.每个构造函数中都有一个prorotype原型对象 # 2.prorotype原型对象中有一个constructor属性,它指向的是它本身所属的构造函数 # 3.每个实例都有一个__proto__属性,它指向的是构造函数的prototype原型对象 # 4.因为每个实例都有一个__proto__属性,所以Student构造函数的构的原对象也有__proto__,它就是Object的原型对象 # 5.Object的原型对象的__proto__属性是空 # 得出结论: # .当获取实例的属性的时候,先从自身直接属性中获取值,如果没有就去__proto__原型对象中获取,原型对象中也没有的话就到Object原型对象中去找,再没有就报错,因为原型对象的__proto__是null。 # ..注意:在实例中设置属性的时候不会影响原型对象。因为设置的时候实例本身不具备属性是直接新增属性,并不会修改原型中的属性。 # ...你可以直接通过实例.constructor属性可以判断实例是属于哪个构造函数的。 # 如果需要在原型对象中设定多个函数的话,你可以这么做 function Student(name, age, sex) { this.name = name; this.age = age; this.sex = sex; } Student.prototype = { constructor: Student, # 这里必须设定,不然就没办法找到所属构造函数 sayHi: function () { console.log('大家好,我是' + this.name) } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了