深入浅析js原型链和vue构造函数

一、什么是原型链?

深入浅析js原型链和vue构造函数

简单回顾下构造函数,原型和实例的关系:

每个构造函数(constructor)都有一个原型对象(prototype),原型对象都包含一个指向构造函数的指针,而实例(instance)都包含一个指向原型对象的内部指针.

然鹅,在js对象里有这么一个规则:

  如果试图引用对象(实例instance)的某个属性,会首先在对象内部寻找该属性,直至找不到,然后才在该对象的原型(instance.prototype)里去找这个属性.

少废话,先来看个例子:

function Fun1 () { this.win = "skt" } Fun1.prototype.getVal = function () { return this.win } function Fun2 () { this.other_win = "rng" } Fun2.prototype = new Fun1 () Fun2.prototype.getOtherVal = function () { return this.other_win } let instance = new Fun2() console.log(instance.getVal()) //skt

在上述例子中,有一个很有意思的操作,我们让原型对象指向了另一个类型的实例,即: constructor1.property = instance2

那么他是怎么找到instance.getVal()的?这中间又发生了什么?

  1).首先会在instance1内部属性中找一遍;

  2).接着会在instance1.__proto__(constructor1.prototype)中找一遍,而constructor1.prototype 实际上是instance2, 也就是说在instance2中寻找该属性;

  3).如果instance2中还是没有,此时程序不会灰心,它会继续在instance2.__proto__(constructor2.prototype)中寻找...直至Object的原型对象

搜索轨迹: instance1--> instance2 --> constructor2.prototype…-->Object.prototype

这种搜索的轨迹,形似一条长链, 又因prototype在这个游戏规则中充当链接的作用,于是我们把这种实例与原型的链条称作 原型链

二、prototype 和 __proto__ 都是个啥?

1.prototype是函数才有的属性

let fun = function () {} console.log(fun.prototype) // object console.log(fun.__proto__) // function

2.__proto__是对象具有的属性,但__proto__不是一个规范的属性,对应的标准属性是 [[Prototype]]

let obj = {} console.log(obj.prototype) // underfined console.log(obj.__proto__) // object

我们可以把__proto__理解为构造器的原型,大多数情况下 __proto__ === constructor.prototype      ( Object.create()除外 )

三、new又是个什么鬼?

我们都知道new是一个实例化的过程,那么他是怎么实例化的?下面我们来看一个简单的例子:

function Fun() { this.team = "rng" } let f = new Fun() console.log(f.team) // rng

上述代码中,我们通过new命令实例化了一个叫Fun的函数并赋值给f,这个新生成的实例对象f从构造函数Fun中得到了team属性,其实构造函数内部的this,就代表了新生成的实例对象,所以我们打印f.team的值就取到了rng这个值

这又是哪门子原理?答案如下?

1.创建一个空对象,作为将要返回的对象实例。
2.将这个空对象的原型,指向构造函数的prototype属性。
3.将这个空对象赋值给函数内部的this关键字。
4.开始执行构造函数内部的代码

也就是说,构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。这也是为什么构造函数叫"构造函数"的原因,就是操作一个空对象(即this对象),将其“构造”为所需要的样子。

如果我不加new呢?

function Fun() { this.team = "rng" } let f = Fun() console.log(f) // undefined console.log(team) // rng

我们可以看出上面打印f为undefined,而team却有值,这又是为什么?

其实在这种情况下,构造函数就变成了普通的函数,而且不会被实例.而此时的this指向了全局,team就变成了全局变量,因此我们取到了值

四、 __proto__指向哪?

  说到__proto__的指向问题,还得取决于该对象创建时的实现方式.

  辣么,到底有那些实现方式?

1.字面量方式

let obj = {} console.log(obj.__proto__) // object console.log(obj.__proto__ === obj.constructor.prototype) // true 证明用字面量创建的函数,他的__proto__ 等于 该对象构造器的原型

2.构造器方式

function Func () {} let a = new Func() console.log(a.__proto__) // object console.log(a.__proto__ === a.constructor.prototype) // true

3.Object.create()方式

let obj1 = {name:"rng"} let obj2 = Object.create(obj1) console.log(obj2.__proto__) //{name: "rng"} console.log(obj2.__proto__ === obj2.constructor.prototype) // false

  注: Object.create(prototype, descriptors) 创建一个具有指定原型且可选择性地包含指定属性的对象

五、如何确定原型和实例的关系?

  想要确定原型和实例的关系,坦率的讲,有两种方式:  instance  和  isPrototype()

1.instanceof

  我们用这个操作符来测试实例(instance)与原型链中出现过的构造函数,如果出现过则返回true,反之则为false

  来来来,我们来测试一下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/6e8975c5b161f42cdb9ba4837def99eb.html