JS原型、原型链完全讲解

2022-12-27 0 862

一、第一类

话说在Javascript中所有人皆第一类,第一类是提及类别的两个示例,在JS中提及类别主要包括:Object、Array、Date、RegExp和Function,除此以外,ECMAScript还提供更多3个特定的提及类别:Boolean、Number、String。

与此相反,第一类是某一某一提及类别的示例,新第一类是透过new运算符后跟两个缺省来建立的,缺省这类是两个表达式,或者说该表达式是所致创建第一类的目地而再次出现的。

红豆:

console.log(typeof Object);//function console.log(typeof Array);//function console.log(typeof Date);// function console.log(typeof RegExp);//function var obj = new Object(); var array = new Array(); var date = new Date(); var reg = new RegExp(); console.log(typeof obj);//Object console.log(typeof array);//Object console.log(typeof date);//Object console.log(typeof reg);//Object

二、Function类别

要说ECMAScript中什么最有意思,那莫过于表达式了,而有意思的根源在于——表达式实际上也是第一类,可称为表达式第一类。每个表达式都是Function类别的示例,而且与其他提及类别一样具有属性和方法。由于表达式是第一类,因此表达式名实际上也是两个指向表达式第一类的指针

function fn(params){console.log(params)} //等价于 var fn = new Function(params,console.log(params))

与普通第一类不同的是:

console.log(typeof Function);//function console.log(typeof fn); //function

三、蓝本第一类

在第一节说过,缺省可以用来建立某一类别的第一类,像Object、Array这样的原生表达式,运行时会自动再次出现在执行环境中。我们也可以建立自定义的缺省,从而自定义第一类:

function Person(){ this.name = name; this.age = age; this.sayName = function(){ console.log(this.name) } } var person = new Person(Jim,30);

缺省建立第一类必须透过new运算符来进行,用这种方式建立第一类会经历以下四个过程:

(1)建立两个新第一类;

(2)将缺省的作用域赋给新第一类(让this指向新第一类);

(3)执行缺省中的代码(为新第一类添加属性);

(4)返回新第一类;

无论什么时候,只要建立了两个新表达式,就会根据一组某一的规则为该表达式建立两个prototype属性,这个属性指向表达式的蓝本第一类。在默认情况下,所有蓝本第一类都会自动获得两个constructor(缺省)属性,这个属性是两个指向prototype属性所在表达式(缺省这类)的指针:

Person.prototype.constructor == Person

建立了自定义的缺省之后,其蓝本第一类默认只会取得constructor属性;至于其他方法,则都是从Object继承而来的。当调用缺省new两个示例(第一类)后,该示例内部将包含两个指针(内部属性_proto_),指向缺省的蓝本第一类,这个连接存在于示例和构造表达式的蓝本第一类之间,而不是示例和缺省之间:

person.__proto__ == Person.prototype

之前在一篇博文中发现这样的写法:

person.constructor == Person.prototype

其实示例这类并没有constructor属性,而是示例透过__proto__指向了Person.prototype,而constructor属性是Person.prototype上的属性,指向缺省这类。

蓝本第一类其实是两个普通的第一类,但是Function.prototype除外,它是两个表达式第一类,但它很特定,没有prototype属性(前面说道表达式第一类都有prototype属性))

function Person(){}; console.log(Person.prototype) //{constructor:f}具有constructor属性的第一类 console.log(typeof Person.prototype) //Object console.log(typeof Function.prototype) // Function,这个特定 console.log(typeof Object.prototype) // Object console.log(typeof Function.prototype.prototype) //undefined

四、蓝本链

蓝本链是实现继承的主要方法,其基本思想是:利用蓝本(prototype)让两个提及类别继承另两个提及类别的属性和方法。

回顾一下缺省、蓝本和示例的关系:

(1)每个缺省都有两个蓝本第一类;

(2)蓝本第一类都包含两个指向构造表达式的指针(constructor);

(3)示例都包含两个指向蓝本第一类的内部指针(__proto__)

如第三节所说,JS 在建立第一类(不论是普通第一类还是表达式第一类)的时候,都有两个叫做__proto__ 的内置属性,用于指向建立它的缺省的蓝本第一类。

第一类 person 有两个 __proto__属性,建立它的缺省是 Person,缺省的蓝本第一类是 Person.prototype ,所以:

person.__proto__ == Person.prototype;

如果我们让蓝本第一类等于另两个第一类的示例,结果会怎样呢?此时的蓝本第一类将包含两个指向另两个蓝本第一类的指针,相应的另两个蓝本第一类中也包含着另两个缺省的指针。

即是:

function Person1(){}; function Person2(){}; var person1 = new Person1(); var person2 = new Person2(); person1.__proto__ == Person1.prototype; Person1.prototype.constructor == Person1; person2.__proto__ == Person2.prototype; Person2.prototype.constructor == Person2; //如果 Person2.prototype = new Person1(); //那么 Person2.prototype.__proto__ == Person1.prototype Person1.prototype.constructor == Person1

假如另两个蓝本又是另两个类别的示例那么上述关系依然成立,如此层层递进,就构成了示例与蓝本的链条。

然鹅,我们都知道,所有的提及类别默认都继承了Object,这个继承也是透过蓝本链实现的。大家要记住,所有表达式的默认蓝本都是Object的示例,蓝本第一类是两个普通第一类,两个普通第一类的缺省是Object。因此默认蓝本都会包含两个内部指针,指向Object.prototype,所以最终的蓝本链:

person.__proto__ == Person.prototype; Perosn.prototype.__proto__ == Object.prototype; Object.prototype.__proto__ === null

五、再来说说Function

回头看看第一节,第一类是使用 new 运算符后跟两个缺省来建立的,构造器不仅仅有 Object,也可以是 Array,Date,Function等,既然他们都是表达式,辣么它们的__proto__又指向谁呢?相信聪明的你已经猜到了,是Function.prototype,它是两个空表达式(Empty function)

Number.__proto__ === Function.prototype // true Number.constructor == Function //true Boolean.__proto__ === Function.prototype // true Boolean.constructor == Function //true String.__proto__ === Function.prototype // true String.constructor == Function //true // 所有的构造器都来自于Function.prototype,主要包括根构造器Object及Function自身 Object.__proto__ === Function.prototype // trueObject.constructor == Function // true // 所有的构造器都来自于Function.prototype,主要包括根构造器Object及Function自身 Function.__proto__ === Function.prototype // true Function.constructor == Function //true Array.__proto__ === Function.prototype // true Array.constructor == Function //true

插一句:JavaScript中有内置(build-in)构造器/第一类共计12个(ES5中新加了JSON),剩下如Global不能直接访问,Arguments仅在表达式调用时由JS引擎建立,Math,JSON是以第一类形式存在的,无需new。它们的proto是Object.prototype。

上面的情况说明了神马?

所有的构造器都来自于Function.prototype,甚至主要包括根构造器Object及Function自身。故所有构造器都继承了·Function.prototype·的属性及方法。如length、call、apply、bind**

Function.prototype也是唯一两个typeof为function的prototype。其它的构造器的prototype都是两个第一类。

大招来了:

JS原型、原型链完全讲解

知道了所有构造器(含内置及自定义)的__proto__都是Function.prototype,那Function.prototype的__proto__是谁呢?

相信都听说过JavaScript中所有人皆第一类,表达式也是第一类,从哪能体现呢:

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

这说明所有的构造器也都是一个普通 JS 第一类,可以给构造器添加/删除属性等。同时它也继承了Object.prototype上的所有方法:toString、valueOf、hasOwnProperty等。

最后Object.prototype的proto是谁?

Object.prototype.__proto__ === null // true

相信到此大家对于第一类、缺省、蓝本、蓝本链、继承都有了比较明确的了解了,再也不用怕各种原型刁难了。辣条在手,天下我有!!!

JS原型、原型链完全讲解

水平有限,欢迎各位圈内大神多多扔砖,多多指正!!

本文借鉴了:

1、《Javascript高级程序设计》

2、最详尽的 JS 蓝本与蓝本链终极详解,没有「可能是」

相关文章

发表评论
暂无评论
官方客服团队

为您解决烦忧 - 24小时在线 专业服务