前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js中的原型和原型链

js中的原型和原型链

原创
作者头像
用户10562852
发布2023-05-21 17:32:44
1.1K0
发布2023-05-21 17:32:44
举报
文章被收录于专栏:前端不难前端不难

一、原型

1、prototype和constructor

在js中每个函数(非箭头函数,一般关于原型的有关知识我们都只考虑构造函数)都会拥有一个 prototype 属性,该属性值是一个对象,我们称之为原型对象。原型对象上默认会有 constructor 属性,指向该构造函数。创建原型的主要目的是为了对象实例共享属性和方法。

代码语言:javascript
复制
function Person() {
	this.name = 'zs'
}
Person.prototype.age = 12;
Person.prototype.getSome = function() {return false}
let p = new Person()
console.log(Person.prototype.constructor === Person) // true
console.log(p) // Person {name: 'zs'}
console.log(p.age) // 12
console.log(p.getSome()) // false

上面代码中实例对象 p 继承了 Person 原型对象上的方法和属性、如果在创建一个 实例对象同样可以继承该构造函数原型上的属性和方法,实现了数据共享。

2、__proto__

每次调用构造函数创造一个新实例,这个实例内部的 [[Prototype]] 指针就会被赋值为构造函数的原型对象。我们可以通过 __proto__ 属性(隐式原型,每个对象都有该属性),访问对象的原型(上面代码有展示出来)。从而实例对象域构造函数之间有了直接的联系。

编辑

代码语言:javascript
复制
function Person() {
	this.name = 'zs'
}
Person.prototype.age = 12;
Person.prototype.getSome = function() {return false}
let p = new Person()
console.log(Person.prototype === p.__proto__) // true

二、原型链

原型链:《JavaScript高级程序设计》中的描述是:每个构造函数都有一个原型对象,如果该原型是另一个类型的实例呢?那就意味着这个原型本身有一个内部指针指向另一个原型,相应地另一个原型也有一个指针指向另一个构造函数。这样就在实例和原型之间构造了一条原型链。这就是原型链的基本构想。

代码语言:javascript
复制
function Person() {}
console.log(Person.prototype)

在控制台中分析打印出的上面的代码:最外层的对象是 Person.prototype

​编辑

上文中我们说到每个对象都有 __proto__,那么原型对象也不例外。

原型链中的查找机制:实例对象上找不到指定属性,就从该原型对象上找,如果还是找不到就到该原型对象上的原型上去找,。逐层查找,直至查找到原型链的顶端 Object.prototype 它的 __proto 值为 null。

代码语言:javascript
复制
// 依次注释掉下面三点下的代码进行调试不难理解原型链
function Person() {
	// 1.先从实例对象自身查找name属性
	// this.name = 'zs'
}
// 2.实例对象没有name属性的话查找该原型对象上的属性
// Person.prototype.name = 'lisi';
// 3.如果还没有就继续查找,直至查找到原型链的最顶端Object.Prototype
Person.prototype.__proto__.name = 'wangwu';
const p = new Person()
console.log(p.__proto__.__proto__.name) // wangwu
console.log(Person.prototype.__proto__ === Object.prototype) // true

三、__proto__扩展

不再推荐使用该特性。虽然一些浏览器仍然支持它,但也许已从相关的 web 标准中移除,也许正准备移除或出于兼容性而保留。请尽量不要使用该特性。

当 Object.prototype.__proto__ 已被大多数浏览器厂商所支持的今天,其存在和确切行为仅在 ECMAScript 2015 规范中被标准化为传统功能,以确保 Web 浏览器的兼容性。为了更好的支持,建议只使用 Object.getPrototypeOf()。

注意点:通过现代浏览器的操作属性的便利性,可以改变一个对象的 [[Prototype]] 属性,这种行为在每一个 JavaScript 引擎和浏览器中都是一个非常慢且影响性能的操作,使用这种方式来改变和继承属性是对性能影响非常严重的,并且性能消耗的时间也不是简单的花费在 obj.__proto__ = ... 语句上,它还会影响到所有继承来自该 [[Prototype]] 的对象,如果你关心性能,你就不应该在一个对象中修改它的 [[Prototype]]。

关于Object.getPrototypeOf()

返回指定对象的原型(内部[[Prototype]]属性的值),参数为要返回其原型的对象。

代码语言:javascript
复制
const prototype1 = {};
const object1 = Object.create(prototype1); // 该方法下面有描述

console.log(Object.getPrototypeOf(object1) === prototype1); // true

关于Object.setPrototypeOf()

Object.setPrototypeOf() 方法设置一个指定的对象的原型(即,内部 [[Prototype]] 属性)到另一个对象或 null。

第一个参数是:要设置其原型的对象;第二个参数是:该对象的新原型(一个对象或 null)。

代码语言:javascript
复制
function Human(name, level) {
  this.name = name;
  this.level = level;
}

function SuperHero(name, level) {
  Human.call(this, name, level);
}
Human.prototype.getName = function() {
	return this.name;
}
Object.setPrototypeOf(SuperHero.prototype, Human.prototype);
let hero = new SuperHero('zs', 2);
console.log(hero.getName()) // zs

// 注意:如果使用类创建的话可以直接使用 extend 关键字实现继承

Object.create()

Object.create() 方法用于创建一个新对象,使用现有的对象来作为新创建对象的原型(prototype),返回一个带着指定原型对象的新对象。

代码语言:javascript
复制
let objPrototype = {}
let obj = Object.create(objPrototype)
console.log(obj) // {}

三、关于原型中各种指向问题总结

前置知识:所有构造函数其实里面都有 prototype 和 __proto__ 这两个属性,所以 Object 和 Function 就是一个构造函数(我的理解)可能不严谨但是对于我们理解这里面的指向问题会很有帮助,为什们会有这句观点?因为之前我在看其他相关的文章解释的时候,一会儿是 Object.__proto__,一会儿又是 Object.prototype,有点绕脑子,所以总结出来了上面的观点。

1.关于构造函数的 __proto__属性

任何构造函数的 __proto__ 都是 Function.prototype ,所以 构造函数.__proto__ === Function.prototype

代码语言:javascript
复制
function Person() {}
console.log(Person.__proto__ === Function.prototype) // true
console.log(Function.__proto__ === Function.prototype) // true
console.log(Object.__proto__ === Function.prototype) // true

2.关于实例对象的 __proto__

实例对象的 __proto__ 指向创建这个实例对象的构造函数,这个知识点大家都应该没得问题

代码语言:javascript
复制
let p = new Person()
console.log(p.__proto__ === Person.prototype) // true

3.任何对象都是Object的实例

所以 xxx.prototype.__proto__ === Object.prototype,但是这里要注意Object.prototype 这个最顶级的原型对象,不由任何构造函数创建,其 Object.prototype.__proto__ === null

代码语言:javascript
复制
function Person() {}
console.log(Person.prototype.__proto__ === Object.prototype) // true
console.log(Function.prototype.__proto__ === Object.prototype) // true
console.log(Object.prototype.__proto__ === null) // true

以上就是关于原型及原型链的各种问题,希望能够帮助到大家,还有不明白的可以私信我,或者留言,加油!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、原型
    • 1、prototype和constructor
      • 2、__proto__
      • 二、原型链
      • 三、__proto__扩展
        • 关于Object.getPrototypeOf()
          • 关于Object.setPrototypeOf()
            • Object.create()
            • 三、关于原型中各种指向问题总结
              • 1.关于构造函数的 __proto__属性
                • 2.关于实例对象的 __proto__
                  • 3.任何对象都是Object的实例
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档