学习js中的原型链

学习!!!!!!

js不是一个面向对象编程语言(妈的,注孤生)。但是其创始人又设计一个原型链这么个鬼玩意来模仿面向对象编程,就很坑爹。

首先先了解一下js中的一个重要概念:所有的对象都是由函数创建的,js中的一切引用类型都是对象,包括Array,Object,Function等

 

我看过知乎一个文章:JavaScript 世界万物诞生记

这边文章中作者用言简意赅的语言就形象的描写了js中的原型链。

 

在这里我是重复一遍,以自己的语言,自己的理解再加深一遍自己的印象。

 

学习原型链之前有两个特别重要的概念:

  1.原型prototype。 每一个函数都有一个原型属性。

  2.隐式原型__proto__。每一个对象都有一个隐式原型属性,不过一般用不到。

  函数也是对象,所以函数不仅有 原型 ,也有 隐式原型。

js中,所有的对象都是由函数创建的,并且是通过 new Function 的方式创建

  例如:

var obj = {a:1}

  这相当于:

var obj = new Object()
obj.a = 1

  再比如:

var arr = [1,2]

  这相当于:

var arr = new Array(1,2)

我们先看一下什么是原型,什么是隐式原型。

  在浏览器中我们运行以下代码:

function A(){
  this.a = 1
}
console.log(A.prototype)

  看一下结果:

  看的出来,A.prototype 也是一个对象,其中包含 constructor, __proto__等属性。

  但是这个 constructor 是干嘛的呢?这个就是构造函数,也就是函数本身。

 

  我们使用上面定义的方法A创建一个对象出来:

var a = new A()
console.log(a)
console.log(a.__proto__)

 

  看一下浏览器打印出来的结果:

  看上图中打印出来的结果,是不是感觉很眼熟,对,没错,跟上面打印出来的 A.prototype 好像,简直一模一样。

  那么我们再运行下面的代码:

console.log(a.__proto__ === A.prototype)

  看结果:

  果然,a.__proto__  就是 A.prototype。

  这其实就是函数创建对象过程中的最后一步:

var a = new A() =====>

其实就是:

var a = {}
A.call(a)
a.__proto__ = A.prototype

 

  这就是js中函数创建对象的过程。

牢记一下四点:

  1. 对象的 __proto__ 指向创建该对象的函数的 prototype

  2. 所有对象的 prototype 是一个 Object 类型的对象

    这里有个特殊的例子: 因为函数也是对象,所以函数也是由函数创建,创建函数的函数是 Function,有点绕。

    其中Function.prototype === Function.__proto__ 。而且 Function.prototype 是一个 Function 类型的。

  3. 所有 Function 类型的对象的 __proto__ 都会指向 Function.prototype,也是一个 Function 类型

  4. 所有 Object 类型的对象的 __proto__ 最终都指向 Object.prototype

    这里也有一个特殊的例子:Object.prototype.__proto__ 是 null

在js中,String,Number,Boolean等基础类型也有 __proto__ 属性。

var a = 1,b = 'ss',c = true
console.log(a.__proto__) 
console.log(b.__proto__) 
console.log(c.__proto__) 

  打印一下结果:

 

js里面的引用类型常用的有 Array, Object, Function等等。

  所以为了区分js中的引用类型,js有一个关键词:instanceof。

  typeof 只能区分基础类型和引用类型,对于引用类型更细致划分就无能为力了。而 instanceof 能准确的判断出是什么类型。

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

  浏览器运行一下代码:

  这里是 true ,因为 f1 的类型就是 Foo。

介绍一下instanceof的判断机制:

  instanceof 两个参数,左边的为 A,右边的为 B。运行时会沿着 A 的 __proto__ 开始查找,如果找到了 B 的 prototype,则返回 true ,若找到了终点(Object.prototype.__proto__)也没有找到,则返回false。

  再看上面这段代码,首先判断 f1.__proto__ === Foo.prototype , 这里判断为 true ,直接返回 true。

  再来一段代码:

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

 

  看结果:

  

  instanceof 判断时,先判断 f1.__proto__ === Object.prototype ,判断为 false,然后继续判断 f1.__proto__.__proto__ (f1.__proto__是Object类型,Object类型的 __proto__ 都等于 Object.prototype) === Object.prototype,判断为true,返回true。

  再来一段代码:

function Foo(){}
var f1 = new Foo()
console.log(f1 instanceof Function)

  看结果:

  结果为false。因为 f1 是 Object 类型的。

  但是作为一个初学者,还是一步一步剖析一下为什么是false。

首先判断:f1.__proto__ === Function.prototype

判断为false

继续判断 Foo.prototype__proto__ === Function.prototype

判断为false

继续判断 Object.prototype__proto__ === Function.prototype

判断为false

已经到达最顶端 Object.prototype.__proto__ , 返回最后的结果false

 

   再最后看一下 Object 和 Function 的相爱相杀。

console.log(Object instanceof Function) // true , 因为函数类型的 __proto__ 都指向 Function.prototype
console.log(Function instanceof Function) // true , 因为 Function.__proto__ 指向 Function.prototype
console.log(Function instanceif Object) // true , 因为 Function.__proto__.__proto__ 指向 Object.prototype
console.log(Object instanceof Object) //true 因为 Object.__proto__.__proto__ 指向 Object.prototype

 

 

上面介绍了 instanceof ,下面介绍一下原型链。

  在上面 instanceof 从当前对象的 __proto__ 判断到 Object.prototype.__proto__,原型链也类似于这样,也是一个链子。

  当访问一个对象的属性时,先在对象的基本属性中查找,如果没有,再沿着__proto__这条链向上找,这就是原型链

function Foo(){}
var f = new Foo()
f.a = 1

Foo.prototype.a = 10
Foo.prototype.b = 20

console.log(f.a) 
console.log(f.b)
console.log(f.c)
console.log(f.hasOwnProperty('a'))
console.log(f.hasOwnProperty('b'))

  看一下结果:

  在上图中可以看到 f.a 是 1,f.b 是 20,f.c 是 undefined。

  因为对象 f 有自己的属性 a 为 1,所以 f.a 就是 1,所以 f.hasOwnProperty('a') 为 true。但是 f 没有属性 b,所以 f.hasOwnProperty('b') 为 false,只能去 f.__proto__ 也就是 Foo.prototype 中去找属性 b,在这里找到了 b = 20,所以打印出来是20。

  至于 f.c ,因为 f 没有属性 c ,Foo.prototype 也没有属性 c ,Foo.prototype.__proto__ 也就是 Object.prototype 也没有属性 c ,所以返回 undefined。

关于原型链,谨记两点:

  1. 因为所有对象的原型链都会找到 Object.prototype,因此所有的对象都有 Object.prototype 的方法

  2. 每一个函数都有 call、apply、bind 方法,因为这些方法是 Function.prototype 的方法,所有的函数原型链都会找到 Function.prototype

 

以上所有就是我关于js中的原型,原型链的学习和总结。

转载于:https://www.cnblogs.com/FraudulentArtists/p/9837622.html

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值