带你深入了解JavaScript原型和原型链

什么是原型

是函数自带的一个属性,它定义了构造函数制造的对象的公共祖先。

原型有什么作用

构造函数 new 出来的对象会隐式继承到构造函数原型上的属性。

例如

我要造车,车里面有一些固定属性: name, lang, height

代码

ini 复制代码
function Car(color, owner) {
    this.name = 'su7'
    this.lang = 5000
    this.height = 1400
    this.color = color
    this.owner = owner
}

let tian = new Car('black', 'tiantian')
console.log(tian.name);

name lang height 每次new这个构造函数这些固定的属性都要重复执行,造成浪费。

ini 复制代码
Car.prototype.name = 'su7'
Car.prototype.lang = 5000
Car.prototype.height = 1400


function Car(color, owner) {
    this.color = color
    this.owner = owner
}

let tian = new Car('black', 'tiantian')
let Li = new Car('purple', 'Li')
console.log(tian.name);

使用prototype可以把 name lang heigh 变成隐式的属性,直接访问看不到,需要tian.name。当构造函数要批量造对象的时候,那些固定的属性没有必要写在构造函数里。可借助原型(prototype)写在函数体外。

实例对象可以修改显示继承到属性,无法修改隐式继承到的属性(原型上的属性)

ini 复制代码
Car.prototype.product = 'xiaomi'


function Car() {
    this.name = 'su7'
}

let car = new Car()

car.name = '保时捷'
car.product = 'huawei'

这段代码里的 product 并没有被修改,只是新加入了一个属性:product : 'huawei'。

实例对象无法给原型新增属性

不能写car.nickname = 'yan', 应该写成Car.prototype.nickname = 'yan'。

实例对象无法删除原型上的属性

ini 复制代码
Car.prototype.product = 'xiaomi'


function Car() {
    this.name = 'su7'
}

let car = new Car()
car.product = 'huawei'

delete car.product

delete car.product无法删除原型上的product属性,应该写成 delete Car.prototype.product。

构造器(constructor)

实例对象隐式具有一个属性叫constructor,记录该对象是由谁创建的。

javascript 复制代码
function Car() {

}

let car = new Car()
console.log(car.constructor);

打印结果

即car这个对象是由Car()这个构造函数创建的。

constructor也可以被修改

javascript 复制代码
function Bus() {

}

Car.prototype = {   // 函数原型也是对象
    constructor: Bus
}
function Car() {

}

let car = new Car()
console.log(car.constructor);

打印结果

对象原型

对象的隐式原型等于创建它的构造函数的显示原型

叫显示原型和隐式原型的目的就是为了好区分,本质都是原型。

创建一个html文件,把代码放到浏览器中运行,然后检查,点击console。

xml 复制代码
<script>
    function Person() {

    }

    let p = new Person()
    console.log(Person.prototype); // 函数原型  显示原型

    console.log(p.__proto__) // p.__proto__ (双底杠)对象的原型  隐式原型

    // Person.prototype == p.__proto__
</script>

结果

对象用自己继承构造函数体里面的属性,对象用自己的原型来接受函数原型上的属性

xml 复制代码
<script>
    Person.prototype.say() = function() {
        console.log('hello');
    }
    function Person() {
        this.name = 'Tom'
    }

    let p = new Person()
    // 对象 p
     // p = {
    //     name: 'Tom',
    //     __proto__: Person.prototype
    // }
    console.log(p.say());
</script>

能打印出'hello',说明实例对象p是能访问构造函数原型上的属性,怎么访问的呢?通过其构造函数的显示原型来访问。

查找规则

js引擎在查找属性时,会先查找对象显示具有的属性,找不到,再查找对象的隐式原型。

构造函数显示原型的隐式原型等于Object()的显示原型

xml 复制代码
<script>

    function Person() {

    }
    let p = new Person()
    console.log(Person.prototype);
    p._proto_ = Person.prototype
    person.prototype.__proto__ = Object.prototype
</script>

\[prototype]是隐式原型,Person.prototype对象是由Object()创建的,所以 person.prototype.__proto __ = Object.prototype

为什么方法能够直接被调用?

javascript 复制代码
 Array.prototype.push = function() {}
    function Array() {

    }
    
    var arr = []
    arr.push(1)
    

arr能够直接调用push方法是因为这门编程语言内已经在Array()这个构造函数的原型里面加入了一个push方法。

原型链

js引擎在查找属性时,会顺着对象的隐式原型向上查找,找不到,则查找到隐式原型的隐式原型,一直向上,直到找到null为止,这种查找关系,称之为原型链。

javascript 复制代码
GrandFather.prototype.say = function() {
    console.log('haha');
}
function GrandFather() {
    this.age = 60
    this.like = 'drink'
}

Father.prototype = new GrandFather()
function Father() {
    this.age = 40
    this.function = {
        card: 'visa'
    }
}

Son.prototype = new Father()
function Son() {
    this.age = 18
}

let son = new Son()
// console.log(son.age); // 18
// console.log(son.function);
// console.log(son.like);
console.log(son.say());

打印结果

使用Object.create()创建没有原型的对象(不是所有对象都有原型)

xml 复制代码
<script>

    let a = {
        name: 'Tom'
    }

    let obj = Object.create(a) // 创建一个新对象,让新对象隐式继承 a 对象的属性
    console.log(obj);

</script>
相关推荐
我家猫叫佩奇2 小时前
🦭 厌倦了千篇一律的线性图标?Naive Icons 正式开源
前端·javascript·css
梦诺5 小时前
vue3 keepAlive+记录滚动条
前端·javascript·vue.js
天若有情6736 小时前
开源轻量双语工具|一键批量查询 NPM 包历史下载量,支持按作者批量统计
javascript·npm·github pages·开源工具·netlify·前端开源·npm克隆量
福兮说7 小时前
纯前端把图片压缩到指定体积:canvas.toBlob 配合二分查找
前端·javascript·canvas·图片处理
志尊宝7 小时前
Vue3 零基础每日笔记(018):按键与鼠标修饰符——回车搜索、Ctrl+S 保存这样写
javascript·vue.js·笔记
可乐鸡翅yeah_8 小时前
HLS流媒体首屏起播慢深度优化,从分片、索引、播放器全链路调优
开发语言·javascript·ecmascript·m3u8·m3u8在线
开开心心就好9 小时前
低年级识字练笔顺工具,电脑和安卓端都能用
前端·javascript·网络·安全·scala·erlang·语音识别
杨利杰YJlio9 小时前
ITSK PE 26U5 测试版解读:组件完善、VMD 修复与服务器支持边界
前端·javascript·后端
夏幻灵9 小时前
Vue / React 列表渲染中的 key:为什么没有 key,Checkbox 可能“对号跑错”?
前端·javascript·vue.js
YWL9 小时前
vue-time-axis-plus进阶:双进度条+跨空白续播+播放指针,打造专业级监控回放体验
前端·javascript·vue·时间轴