js原型链和继承的理解

JavaScript016

js原型链和继承的理解,第1张

Object() Function() Array() 等等都为构造函数。

Js 面向对象与传统oop 有些不同,语法较高级 语法糖封装。

This 为指针。指向this作用域的调用者

1.原型继承链顶端为Object 。Js函数是对象

2.当读取对象中的属性时,先去实例本身中搜索,如搜索不到则去指向的原型中搜索

1.原型的存在意义在于实现继承共享,是在构造函数中定义的一个成员对象,在下次实例化时不需要在构造函数中定义成员 就可实现实例共享方法属性。

例子:通常为。构造函数.prototype.xxx=我想实现实例继承的东西 -》 new 构造函数 -》新实例a对象.原型指针指向构造函数的xxx对象(引用类型)

例子:Array 不等于 Array() 原因 Array为一个函数,而Array()为一个构造函数调用语句,故Array拥有prototype对象用于实例的共享继承,Array()产生一个实例 故只能拥有prototype对象的私有指针 proto

2.在使用原型继承时 不能使用字面量 构造函数.prototype={} 的方式重写原型对象 。因为会导致该原型对象的constructor属性被重写,在生成的实例中导致constructor指向Object并且会切断之前原型对象的联系,破坏原型链。

3.JavaScript 主要通过原型链实现继承。原型链的构建是通过将一个类型的实例赋值给另一个构造函数的原型实现的

例子:

xxx实例. proto -》function xxx()构造函数.prototype对象故xxx. proto === xxx.prototype

xxx.prototype. proto -》Object.prototype因为所有对象都为Object函数构造来的。故xxx.prototype. proto ===Object.prototype。

Object.prototype. proto 为原型链顶端 proto 定义了尚未使用所以为null故Object.prototype. proto ===null约定俗成。

instanceof 用来判断某实例是否为某构造函数的实例

isPrototypeOf 用于判断某实例是否拥有某构造函数的原型对象指针

1.原型模式有忽略构造函数定义初始值步骤及原型中操作引用类型的缺点。

所以需要组合使用 构造函数模式+原型模式 来创建实例。在构造函数中定义实例的属性,而需共享的方法就定义在原型对象中。

继承:在子构造函数中调用 父.call(this, name)实现构造函数之间的属性继承。使用 子.prototype = new 父()子.prototype.constructor = 子实现方法的继承。

2.如要在生产环境下的构造函数新增方法(如Array) 需要使用一个类似于工厂函数的寄生构造函数模式 在构造函数中返回一个修改后的对象

其实简单来说,原型就是一个对象对另一个对象的引用。

然后其是怎么联系起来的呢,是通过prototype。对就是这个,给你一个例子

var obj = {

a: 2

}

var myObj = Object.create(obj)

console.log(myObj.a) // 2

console.log(myObj === obj)  // false

console.log(Object.getPrototypeOf(myObj) === obj)  // true

Object.getPrototypeOf(myObj).a = 4

console.log(obj.a)  // 4

通过上面的例子,你可以看到,myObj的原型就是obj!然后obj的原型是哪个呢,是Object.prototype。实际上通过上面,你就能知道,原型原理上是对于另一个对象的引用,通过引用吧几个对象给串联起来调用。

那么你的第二个问题马上又来了,可能也是你关心的问题,类和原型的关系是啥呢?

实际上,类在实例化的时候,也就是通过new来创建一个对象的时候,是分为以下几步的:

创建一个全新的对象

这个新对象会被执行prototype连接

新对象绑定到函数调用的this

如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象

这个就是new实例化的时候,所做的一些步骤,那么你其中有几个需要注意的点:

如果有return并且返回的是一个对象的话,则直接返回return后的那个对象。

反之,则新建一个对象。

并且吧函数的prototype引用到新建对象的prototype中。

这个怎么理解呢?再给你一个例子,可能例子更直观一些:

var protoObj = {

b: 10

}

function Foo() {}

Foo.prototype = protoObj

var a = new Foo()

console.log(Object.getPrototypeOf(a) === Foo.prototype)  // true

console.log(Object.getPrototypeOf(a) === protoObj) // true

console.log(a.b) // 10

通过这个例子,你可以看出来,实际上类实例化的过程,其中有一项,就是把其构造好的对象的prototype和类的prototype做关联。因为做好了引用关联,所以构造好的对象可以使用原类里面的原型方法。

这个也讲完了,那么你可能会对class比较感兴趣,想知道class是怎么做的,实际上,class更多,我理解上就是上面类似于Foo()类的一种语法糖,当然也不仅仅是语法糖,但是大体原理是没啥区别的,所以,上面所说的,对于class也同样适用

好啦,如果你对原型和类实例化有更多想了解的,可以给你两篇文章,参考一下:

Javascript基础之-原型(prototype)

Javascript基础之-this

本文主要参考了 MDN文档 和 知乎讨论 。

在js中,大部分东西都是对象,数组是对象,函数也是对象,对象更加是对象。 不管我们给数组和函数定义什么内容,它们总是有一些相同的方法和属性 。比如说hasOwnProperty(),toString()等:

这说明一个对象所拥有的属性不仅仅是它本身拥有的属性,它还会从其他对象中继承一些属性。当js在一个对象中找不到需要的属性时,它会到这个对象的父对象上去找,以此类推,这就构成了对象的原型链 。理解js的原型链对使用js的对象非常有帮助。

让我们通过一个例子由浅到深地理解原型链:

这是我们经常使用的创建对象的方式,将共同的方法放到Foo.prototype中,所有实例都共有这个方法了。

这是怎么实现的呢?我们看下面这张图的第一行:

我们定义的show函数在Foo.prototype中,当我们执行f1.show()时,js发现f1本身没有show这个属性,所以它就到f1的原型(也就是__proto__指向的对象)去找,找到了就可以调用。

图片第一行告诉了我们4点:

我们先看看Foo的原型吧!Foo是一个函数,它的构造函数是js内部的function Function(),Function的prototype指向了一个对象Function.prototype,因此Foo的__proto__就指向了Function.prototype,如图。

我们继续深入下去,Function.prototype这个对象,它就是一个普通的对象,它的构造函数是js内置的function Object(),function Object()的prototype指向Object.prototype,因此Function.prototype.__proto__就指向Object.prototype,这个对象中定义了所有对象共有的属性,比如我们之前说的hasOwnProperty()和toString()等。

Object.prototype就是原型链的终点了,它的__proto__是null,js查找属性时,如果到这里还没有找到,那就是undefined了。

到这里就不难理解为什么我们说在js中,函数也是对象了,它就是继承自对象的!

如果如有疑问,欢迎指出!