likes
comments
collection
share

JS小知识:原型与原型链

作者站长头像
站长
· 阅读数 34

JavaScript中的原型(Prototype)机制是其面向对象编程的核心特性之一,它允许对象之间共享属性和方法,从而实现继承。本文将从浅入深地解析原型、原型链、以及一些特殊情况下的应用,旨在让你对这一概念有更清晰的理解。

JS小知识:原型与原型链

原型(显示原型)

每个JavaScript函数都有一个名为prototype的属性,这是一个对象,用于存储所有通过该函数构造出的对象所共享的属性和方法。当使用new关键字基于某个构造函数创建一个实例化对象时,这个实例化对象会自动链接到构造函数的prototype对象上,这便是原型继承的基础。而该原型指的是函数的原型prototype

function Person() {}
Person.prototype.say = function() { console.log('Hello'); };

在这个例子中,所有通过new Person()创建的实例化对象都会继承构造函数的原型上的say方法。

隐式原型和原型链

每个JavaScript对象(除null外)都有一个内部属性[[Prototype]],通常可以通过__proto__访问(隐式原型__proto__指向的是对象的显示原型prototype)。当访问一个对象的属性或方法时,如果对象本身没有,则引擎会继续在其[[Prototype]]指向的对象中寻找,这一过程形成了一条链,即原型链

JS小知识:原型与原型链

let p = new Person();

对于p来说,其原型链上首先查找自身的属性,若未找到,则会沿着p.__proto__ -> Person.prototype -> Object.prototype -> null这条链进行查找。

也就是说,v8在查找对象的属性时,如果没找到,就会顺着对象的隐式原型往上查找,如果还找不到,再顺着隐式原型的隐式原型往上找,直到找到null为止,在这个过程中,但凡有一个步骤能找到,就会返回值。这个链状的查找过程称为原型链

是不是所有的对象都有原型??

答案当然是,并非所有对象都有原型。使用Object.create(null)可以创建一个没有原型(__proto__会指向null)的对象,这样的对象不会继承任何默认的Object方法。

修改原型的属性

实例化对象是不可以修改原型上的属性的

Person.prototype.like = '听歌';
let p = new Person();
p.like = '撸铁'; 
let s = new Person()
console.log(p) 
console.log(s.like) 

由后面实例化出来的s对象中可以看出,当执行p.like的时候,并不是修改原型上的属性,而是在p对象上添加一个like属性并赋值为撸铁

多级继承示例

多级继承展示了如何通过原型链实现深层次的属性和方法继承,每个子类通过其原型链连接到父类的原型。

    Grand.prototype.lastname = '张';
    function Grand(){
        this.name='三'
    }
    Father.prototype=new Grand()
    function Father(){
        this.age=40
    }
    Son.prototype=new Father()
    function Son(){
        this.like='coding'
    }

    let son = new Son();
    // console.log(son.like)
    // console.log(son.age)
    console.log(son.name)

下面我将描述出输出son.name时的查找路线:

JS小知识:原型与原型链

原型链的实践与注意事项

  • 修改数组的push方法展示了原型链上方法覆盖的原理。
// var arr=[1,2,3]  
// arr.push(4)//1,2,3,4
// 原型链

Array.prototype.push = function(){
    this[0]='a'
}
var arr=[1,2,3]  //  new Array() --> this 
arr.push(4)

console.log(arr)//4,2,3
  • Number.prototype.toString等内建原型方法的调用,说明了即使是最基本的数据类型也是基于原型链实现方法访问的。
var num=1// new Number()
console.log(num.toString())

构造函数与原型对象的区分

构造函数本身也是一个对象,它有自己的属性和方法,这些不通过原型链传递给实例。例如,Foo.b=2设置的是构造函数的静态属性,而非原型属性。

Foo.prototype.a=1
function Foo() {
    // this={

    // }
    // this.__proto__ = Foo.prototype
    // return this
    // b=2
}
Foo.b=2
console.log(Foo);//{b:2}
let f = new Foo();

console.log(f.b);//undefined

最后

总的来说,JavaScript的原型和原型链机制提供了一种灵活而强大的对象继承方式。理解这一机制对于深入掌握JavaScript的面向对象编程至关重要。通过上述示例的逐步分析,我们不仅看到了原型如何让对象共享属性和方法,还见识到了原型链如何构建起对象间属性查找的路径。这将会使我们更好的理解为什么可以调用不属于他身上的属性和方法,便于我们更好的掌握这一门编程语言!!

JS小知识:原型与原型链

转载自:https://juejin.cn/post/7379897208532926518
评论
请登录