前端JavaScript篇之对原型、原型链的理解、原型修改、重写、原型链指向
目录
- 对原型、原型链的理解
- 原型修改、重写
- 修改原型
- 重写原型
- 修改和重写原型的影响
- 案例代码
- 原型链指向
对原型、原型链的理解
原型(Prototype)是JavaScript中每个对象都具有的属性,它包含对象的共享属性和方法。当我们创建一个新对象时,这个对象会从原型继承属性和方法。原型链(Prototype Chain)是由对象组成的链式结构,它用于查找对象的属性和方法。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到匹配的属性或方法。
在JavaScript中,使用构造函数来新建一个对象,每个构造函数都有一个内部的prototype属性,它的属性值是一个对象,包含了可以由该构造函数的所有实例共享的属性和方法。当使用构造函数新建一个对象后,对象内部将会包含一个指向构造函数的prototype属性对应的值的指针,这个指针被称为对象的原型。通过原型链,对象可以从原型继承属性和方法。
在访问一个对象的属性时,如果对象内部不存在这个属性,就会去它的原型对象中查找这个属性,并继续通过原型链向上查找,直到找到匹配的属性。原型链的尽头一般是Object.prototype。
通过原型和原型链的机制,可以实现对象的继承和共享属性和方法。原型和原型链是JavaScript中非常重要的概念,对于理解对象的继承和属性查找机制至关重要。
原型修改、重写
在JavaScript中,可以修改或重写对象的原型。当修改原型时,所有与该原型相关的对象都会继承这一改变。下面是对修改和重写原型的详细描述:
修改原型
修改原型是指向现有原型添加新的属性或方法。我们可以通过给原型对象添加新的属性或方法来实现这一点。
在下面的代码中,我们向Person
构造函数的原型添加了一个新的getName
方法:
function Person(name) {
this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
在这个例子中,我们给Person
构造函数的原型添加了一个新的getName
方法。现在,所有Person
对象的实例都可以使用这个方法。
重写原型
重写原型是指用一个新的对象来替换现有原型。我们可以通过直接赋值一个新的对象给原型来实现这一点。
在下面的代码中,我们用一个新的对象来替换Person
构造函数的原型:
Person.prototype = {
getName: function() {}
}
在这个例子中,我们用一个新的对象来替换Person
构造函数的原型。现在,所有Person
对象的实例都会继承这个新的原型对象。
修改和重写原型的影响
修改和重写原型都会对与原型相关的对象产生影响。当我们修改原型时,所有与该原型相关的对象都会继承这一改变。当我们重写原型时,与原型相关的对象将不再继承原型中的属性和方法,而是继承新的原型对象中的属性和方法。
案例代码
在下面的代码中,我们先修改了Person
构造函数的原型,然后创建了一个Person
对象的实例p
。我们使用__proto__
属性和constructor
属性来检查p
对象的原型和构造函数。
function Person(name) {
this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
接下来,我们重写了Person
构造函数的原型,然后再次创建了一个Person
对象的实例p
。我们再次使用__proto__
属性和constructor
属性来检查p
对象的原型和构造函数。
// 重写原型
Person.prototype = {
getName: function() {}
}
var p = new Person('hello')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // false
我们可以看到,当我们重写原型时,p
对象的构造函数不再指向Person
构造函数,而是指向根构造函数Object
。因此,此时p.constructor === Object
,而不是p.constructor === Person
。为了让p.constructor === Person
,我们需要将它手动指回来,如下所示:
Person.prototype = {
getName: function() {}
}
var p = new Person('hello')
p.constructor = Person
console.log(p.__proto__ === Person.prototype) // true
console.log(p.__proto__ === p.constructor.prototype) // true
- 修改原型是指向现有原型添加新的属性或方法。
- 重写原型是指用一个新的对象来替换现有原型。
- 修改和重写原型都会对与原型相关的对象产生影响。
- 当我们重写原型时,相关对象的构造函数可能会指向根构造函数
Object
,需要手动将其指回来。
原型链指向
在 JavaScript 中,每个对象都有一个原型(prototype)。原型是一个对象,它包含对象的共享属性和方法。当我们创建一个新对象时,这个对象会从原型继承属性和方法。
在 JavaScript 中,对象之间的原型关系构成了原型链。原型链是由对象组成的链式结构,用于查找对象的属性和方法。当我们访问一个对象的属性或方法时,如果该对象本身没有这个属性或方法,JavaScript 引擎会沿着原型链向上查找,直到找到匹配的属性或方法。
对于一个对象p
,我们可以通过p.__proto__
来访问它的原型对象。例如,对于一个Person
对象的实例p
,p.__proto__
指向Person.prototype
。
对于一个原型对象,我们可以通过prototype.__proto__
来访问它的原型对象。例如,对于Person.prototype
,Person.prototype.__proto__
指向Object.prototype
。
对于一个对象p
,我们可以通过p.__proto__.__proto__
来访问它的原型对象的原型对象。例如,对于一个Person
对象的实例p
,p.__proto__.__proto__
指向Object.prototype
。
对于一个对象p
,我们还可以通过p.__proto__.constructor.prototype.__proto__
来访问它的构造函数的原型对象的原型对象。例如,对于一个Person
对象的实例p
,p.__proto__.constructor.prototype.__proto__
也指向Object.prototype
。
对于一个原型对象,我们可以通过prototype.constructor
来访问它的构造函数。例如,对于Person.prototype
,Person.prototype.constructor
指向Person
构造函数。
对于一个对象p
,我们可以通过p.__proto__.constructor
来访问它的构造函数。例如,对于一个Person
对象的实例p
,p.__proto__.constructor
指向Person
构造函数。
function Person(name) {
this.name = name
}
var p = new Person('John')
var p1 = new Person('Mike')
console.log(p.__proto__) // Person.prototype
console.log(Person.prototype.__proto__) // Object.prototype
console.log(p.__proto__.__proto__) // Object.prototype
console.log(p.__proto__.constructor.prototype.__proto__) // Object.prototype
console.log(Person.prototype.constructor.prototype.__proto__) // Object.prototype
console.log(p1.__proto__.constructor) // Person
console.log(Person.prototype.constructor) // Person
注意事项:
-
在 ES6 中,我们可以使用
Object.getPrototypeOf()
方法来获取一个对象的原型对象。例如,Object.getPrototypeOf(p)
可以替代p.__proto__
。 -
在修改原型对象时,需要注意对原型链的影响。如果我们修改了一个原型对象的属性或方法,那么所有继承自该原型对象的对象都会受到影响。
-
在使用原型继承时,需要注意避免出现原型链中的循环引用,否则会导致程序出现死循环。
持续学习总结记录中,回顾一下上面的内容:
在JavaScript中,每个对象都有一个指向另一个对象的链接,这个对象就是我们所说的原型。原型是JavaScript实现继承的核心机制之一。
当我们创建一个对象时,这个对象会自动关联一个原型。如果我们访问一个对象的属性或方法,但是这个对象本身并没有这个属性或方法,JavaScript引擎会沿着原型链向上查找,直到找到匹配的属性或方法为止。
原型链是由对象的原型构成的链式结构,当我们访问一个对象的属性或方法时,JavaScript引擎会沿着这条链去查找对应的属性或方法。
通过修改原型,我们可以给已存在的对象类型添加新的方法或属性。这意味着所有基于这个对象类型创建的对象都可以访问到这些新的方法或属性。
重写原型是指改变一个对象的原型,这样新的原型就会被所有基于该对象类型创建的对象所共享。
原型链的指向是指对象的原型是谁,它决定了对象在查找属性或方法时的搜索路径。一个对象的原型是另一个对象,而这个对象的原型又是另一个对象,以此类推,就形成了原型链。
总的来说,原型和原型链是JavaScript中实现继承的基础,通过它们,我们可以实现对象之间的属性和方法的共享,实现代码的复用,同时也可以通过修改原型和重写原型来扩展和改变对象的行为。