JavaScript —— 原型与原型链

本文深入探讨了JavaScript中的原型和原型链概念。首先介绍了函数的prototype属性及其指向的原型对象,指出每个函数的原型都是Object的实例。接着阐述了原型链的工作原理,当访问对象属性时,会沿着__proto__链查找。此外,讨论了instanceof运算符的判断方式,并通过实例解释了原型链在属性查找和设置中的行为。最后,提供了几个原型链相关的面试题以加深理解。
摘要由CSDN通过智能技术生成

一、原型

先看一段代码

function Fn () {}  // 1
console.log(Fn.prototype)

运行完第一行代码之后,会生成一个叫Fn的构造函数,而这个构造函数中有一个prototype属性,指向的就是这个函数的原型对象

如下图所示:

函数Fn有一个prototype属性,这个属性就指向它的原型对象即Fn.prototype,原型对象又有一个constructor构造器,这个构造器指向Fn函数本身

原型对象里面存放着所有实例对象需要共享的属性和方法

Fn函数的实例化:

let fn = new Fn()

通过new操作符就可以实例化一个fn对象,来看一下他们之间的对应关系。

使用new这个关键字的时候,JS编译器会做四件事情:
1、创建一个新的空的对象
2、把这个对象链接到原型对象上,将构造函数的作用域赋给新对象(因此this就指向了这个新对象)
3、执行构造函数中的代码(为这个新对象添加属性)
4、如果这个函数有返回值,则返回;否则,就会默认返回新对象

实例对象fn会有一个__proto__属性,它指向构造函数Fn的原型。
上面我们看到了一个Fn.protottype里面有一个__proto__属性,那我们来看看它的指向吧

从图可以看到,Fn.prototype.__proto__指向Object.prototype,这就说明每个函数的原型都是Object的实例,也就是说每个函数的原型都是通过 new Object() 产生的。

上面的构造函数和原型对象之间的关系汇成的了一条链。

二、原型链

1、原型链(图解)

* 访问一个对象的属性时,

      * 先在自身的属性中查找,找到返回

      * 如果没有,再沿着__proto__这条链向上查找,找到返回

      * 如果最终没找到,返回 undefined

* 别名:隐式原型链

* 作用:查找对象的属性(方法)

2、构造函数/原型/试题对象的关系(图解)

3、构造函数/原型/试题对象的关系2(图解)

原型链 实际上通过隐式原型链来查找 原型链是来查找对象的属性的,非变量属性
在上面的查找过程,我们提到了最顶层的原型对象,这个对象就是Object.prototype,这个对象中保存了最常用的方法,如toString、valueOf、hasOwnProperty等,因此我们才能在任何对象中使用这些方法。
1、函数的显式原型指向的对象默认是空 Object实例对象(但 Object 不满足)

function Fn() {}
console.log(Fn.prototype instanceof Object)          // true
console.log(Object.prototype instanceof Object)      // false
console.log(Function.prototype instanceof Object)    // true

2、所有的函数都是 function 的实例包含(Function)

console.log(Function.__proto__ === Function.prototype) // true

3、Object的原型对象是原型链的尽头

console.log(Object.prototype.__proto__)   // null

三、原型链的属性问题

1、读取对象的属性值时,会自动到原型链中查找

2、设置对象的属性值时,不会查找原型链,若当前对象中无此属性,直接添加该属性并设置值。

3、方法一般定义在原型中,属性一般通过构造函数定义在对象本身上。

function Fn(){}
Fn.prototype.a = 'xxx'

var fn1 = new Fn()
console.log(fn1.a,fn1)

var fn2 = new Fn()
fn2.a = 'yyy'
console.log(fn1.a,fn2.a,fn2)

四、探索 instanceOf

function Foo(){}
var f1 = new Foo()
console.log(f1 instanceof Foo)      // true
console.log(f1 instanceof Object)   // true

1、instanceof是如何判断的?

* 表达式 A instanceof B
* 如果函数 B的显式原型对象在 A 的隐式原型链上,返回 true,否则返回 false。

2、Function是通过 new自己产生的实例

console.log(Object instanceof Function)    // true
console.log(Object instanceof Object)      // true
console.log(Function instanceof Function)  // true
console.log(Function instanceof Object)    // true

function Foo(){}
console.log(Object instanceof Foo)         // false    

五、原型链相关面试题

测试题1:

Foo.prototype.n = 1
var f1 = new Foo()
Foo.prototype = {
    n:2,
    m:3
}
var f2 = new Foo()

console.log(f1.n,f1.m)
console.log(f2.n,f2.m)

     

测试题2:

var F = function F(){}
Object.prototype.a = function(){
    console.info('a()')
}
Function.prototype.b = function(){
    console.info('b()')
}
var f = new F()
f.a()
f.b()
F.a()
F.b()

三、总结

(一)原型函数

1、函数的 prototype 属性

* 每个函数都有一个 prototype 属性,默认指向一个 Object 空对象(即:原型对象)。
* 原型对象中有一个 constructor 属性,它指向函数对象。

2、给原型对象添加属性(一般都是方法)

* 作用:函数的所有实例对象自动拥有原型中的属性(方法)

console.log(Date.prototype, typeof Date.prototype)

function fun(){}

fun.prototype.test = function (){
    console.log('test()')
}

console.log(fun.prototype)

console.log(Date.prototype.constructor === Date)
console.log(fun.prototype.constructor === fun)

(二)显式原型和隐式原型

1、每个函数都有一个 prototype 属性,即显式原型,指向其函数的原型对象。

2、每个实例对象会有一个 __proto__ 属性, 即隐式原型,指向对象的原型对象

3、对象的隐式原型的值与其对应的构造函数的显式原型值相等。

function Fn(){ // 内部语句
//    this.prototype = {}
}
console.log(Fn.prototype)

var fn1 = new Fn()
console.log(fn1.__proto__)
console.log(Fn.prototype === fn1.__proto__)

1、Object是作为众多new出来的实例的基类 function Object(){ [ native code ] }

2、Function是作为众多function出来的函数的基类 function Function(){ [ native code ] }

3、构造函数的proto(包括Function.prototype和Object.prototype)都指向Function.prototype

4、原型对象的proto都指向Object.prototype (每个函数的原型都是 Object 的实例)

5、Object.prototype.proto指向null

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值