摘要:在中,万物皆对象。在日常中,我们除了经常听到原型这个词之外,还经常会听到原型链这个词,那么这两个词到底有什么关系呢,下面我们就来探究一下。指向的对象往往被称为函数的原型。很简单,委托实际上就是原型链。
在JavaScript中,万物皆对象。每个对象都有一个特殊的内部属性,[[Prototype]](原型)。它是对于其他对象的引用,也就是说它关联到别的对象(如果它不为空)。
在日常中,我们除了经常听到原型这个词之外,还经常会听到原型链这个词,那么这两个词到底有什么关系呢,下面我们就来探究一下。
那首先我们来看一下[[Prototype]]这个特殊的内部属性有什么用呢?我们先来讲一个关于属性访问的一些知识。看下面的代码:
var myObject = { a:1; }; myObject.a; //1
在这里,我们可以清楚的看到Object.a是一个属性访问(访问了Object的a属性),那么深入一下,上面的代码实际上在Object上执行了一个[[Get]]操作。对一个对象执行默认的[[Get]]操作,会首先检查对象,寻找请求的属性,如果找到,就返回相应的值。如果没找到,这个时候对象的[[Prototype]]属性以及它的[[Prototype]]链就需要派上用场了。
先看代码:
var newObject = { a:1; }; var myObject = Object.create(newObject); myObject.a; //1
首先我们可以看到在上面的代码中,a这个属性是不存在myObject这个对象里的,但是最后我们还是得到了a这个属性的值。
var myObject = Object.create(newObject);这行代码就是关键了。它创建了一个对象myObject关联到newObject。也就是说myObject的[[Prototype]]属性关联到了newObject这个对象。[[Get]]操作在对象本身没找到需要的属性后,便顺着这个关联去newObject这个对象里进行查找。
所以在对属性进行查询的时候,就会顺着这个一层又一层的关联,也就是所谓的[[Prototype]]链,对需要的属性进行查找。在[[Prototype]]链找到了就返回属性值或者在链条的末尾都没找到就返回undefined。那么链条的末尾是什么呢?每个普通的[[Prototype]]链的最顶端,是内建的Object.prototype,也就是null。
开头讲到,[[Prototype]]这个属性是把一个对象关联到另一个对象。那么这个关联有什么用呢?
常见的用法那就是所谓的原型继承和委托了。
我们通过代码来理解一下:
function Foo(a) { this.a = a; } Foo.prototype.myA = function() { return this.a; }; function Bar(a,b) { Foo.call(this,a); this.b = b; } Bar.prototype = Object.create(Foo.prototype); Bar.prototype.myB = function() { return this.b; }; var Baz = new Bar( "1", "obj 1" ); Baz.myA(); // "1" Baz.myB(); // "obj 1"
在上面的代码中,最重要的部分就是Bar.prototype = Object.create(Foo.prototype);。这个代码应该会比较眼熟,因为在上面的例子中我们也用到了相似的代码,并且解释说是把一个对象关联到另一个对象上。那么这里我们是把新创建的Bar对象的内部的[[Prototype]]链接到了指定的对象Foo.prototype。
Bar和Foo在这里既是对象也是函数。函数有一个性质:所有的函数默认都会得到一个可以指向任何对象的属性prototype。
指向的对象往往被称为“函数的原型”。每个由调用new Foo()而创建的对象将最终被[[Prototype]]链接到所谓的“函数的原型”。
看段代码来深入了解一下:
function Foo(a){ this.a = a; } var bar = new Foo(2); bar.a; //2 Object.getPrototypeOf(bar) === Foo.prototype; //true
那么为什么调用new Foo()创建的对象可以链接到函数原型呢?这就跟它的实现有关了。
当函数前面加new调用时,会有以下事情完成:
一个全新的对象被创建
这个新的对象会被接入到原型链
这个新的对象被设置为函数调用的this绑定
除非函数有返回对象,否则这个被new调用的函数将自动返回这个新的对象
主要我们要看的是第二点,其他的会在this绑定的文章中讲到。
所以在上面的例子中,调用new Foo()创建bar的时候,bar会得到一个内部的[[Prototype]]链接,链接到Foo.prototype所指向的对象。
在“原型继承”的例子代码中var Baz = new Bar( "1", "obj 1" );也是使用了new来创建对象,从而使baz对象链接到bar.prototype上.
到目前为止,我们提到了2种方法来创建新对象并与其他对象关联:
Object.create()
函数前面加new调用
表面上看好像都可以达到我们的目的,但是第二种方法可能会有意想不到的副作用产生。假如说Foo()这个函数还可以改变状态或者向this添加数据属性等,那么在对象在被创建的时候就会有这些我们可能本身并不需要的东西。
最后用一张图来总结一下原型继承:(图来源:You-Dont-Know-JS)
从图中可以看出,箭头由右至左,由下至上。而[[Prototype]]机制,就是一种存在于对象上的内部链接,指向另一个对象。
事实上,“原型继承”这个词很容易让人产生误会,因为JavaScript中没有类,也就没有继承。实际上,Bar与Foo不能说是继承的关系,用准确点的术语来说,是委托。所以接下来我们就要来了解一下委托了。
很简单,委托实际上就是原型链。比如说新建对象a链接到对象b,a可以使用b的方法,也就是a委托了b(来实现它想要实现的效果)。这样的话直接用Object.create就可以了,不需要再调用new函数了。var a = Object.create(a);
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/93654.html
摘要:看完视频初步认识了一下,以及模块化开发的概念,在此做一下总结。所以应该将功能抽象成模块。并且非常耗性能解决办法,在滚动条正在运动或者已经到达目的地,就不应该执行动画。 前言:在慕课网上跟着视频《侧边工具栏开发》做了一遍,用到了jquery操作DOM,其中,用requirejs管理模块依赖,然后自定义了两个模块它们都依赖jquery,并且其中一个自定义模块依赖另一个,所以要暴露出接口。看...
摘要:最后举两个例子,回顾上面的内容例一改变的是数组元素中属性,由于创建的的指令,因此这里直接由指令更新对应元素的内容。 下面例子来自官网,虽然看上去就比Hello World多了一个v-for,但是内部多了好多的处理过程。但是这就是框架,只给你留下最美妙的东西,让生活变得简单。 {{ todo.text }} ...
摘要:属性这是每个对象都有的隐式原型属性,指向了创建该对象的构造函数的原型。 原型 在JavaScript中,有两个原型,分别是 prototype 和 _proto_注:在ECMA-262第5版中管这个 _proto_ 叫 [[Prototype]] prototype 属性:这是一个显式原型属性,只有函数才拥有该属性。_proto_ 属性:这是每个对象都有的隐式原型属性,指向了创建该对象...
摘要:很多情况下,通常一个人类,即创建了一个具体的对象。对象就是数据,对象本身不包含方法。类是相似对象的描述,称为类的定义,是该类对象的蓝图或原型。在中,对象通过对类的实体化形成的对象。一类的对象抽取出来。注意中,对象一定是通过类的实例化来的。 showImg(https://segmentfault.com/img/bVTJ3H?w=900&h=385); 马上就要到七夕了,离年底老妈老爸...
阅读 953·2019-08-30 14:24
阅读 987·2019-08-30 14:13
阅读 1798·2019-08-29 17:21
阅读 2658·2019-08-29 13:44
阅读 1653·2019-08-29 11:04
阅读 438·2019-08-26 10:44
阅读 2564·2019-08-23 14:04
阅读 908·2019-08-23 12:08