个人JS体系完善(一)
个人js体系整理(一)
一. 原型
js每声明一个function,都有prototype原型,prototype原型是函数的一个默认属性,在函数的创建过程中由js编译器自动添加,也就是说每当生产一个function对象的时候,就有一个原型prototype。按照javascript的说法,function定义的object(对象),是一个很特殊的对象,这个使用function定义的对象与使用new操作符生成的对象之间有一个重要的区别,这个区别就是function定义的对象有一个prototype属性,称之为函数对象,而使用new生成的对象就没有这个prototype属性,称之为普通对象。
图1.1
如上图所示,第一个console结果为undifined,证明了new的对象是没有原型prototype的;第二个console结果为增加原型name以后的原函数,证明了只有函数对象才具有原型prototype;第三个console的结果为’hangzhou’,证明了通过原型增加的属性是存在的;第四个console的结果为’hangzhou’,证明了通过原型增加的属性,是可以在该对象所具有的方法里面进行调用获取到的。
图1.2
如上图所示,如果原函数本身的属性或方法与利用原型增加的属性或方法重名时,默认调用的依旧是该函数对象本身的属性或者方法,即函数本身的属性或者方法的优先级高于原型的属性或者方法。
二. 原型链
官方对于原型链的解释是原型链是实现继承的主要方法,其基本思想是利用原型让一个引用类型继承另一个应用类型的属性和方法。通俗一些理解,每个对象都会在其内部初始化一个属性,就是prototype(原型),当我们访问一个对象的属性时, 如果这个对象内部不存在这个属性,那么他就会去prototype里找这个属性,这个prototype又会有自己的prototype, 于是就这样一直找下去,也就是我们平时所说的原型链的概念。
提到原型链,就要提一个词_proto_,它是基本对象的属性,相对应的就是每一个函数对象都有一个自己的prototype原型,由于函数对象也属于基本对象,所以函数对象也有_proto_,每当去定义一个prototype的时候,就相当于把该实例的__proto__指向一个结构体,那么这个被指向结构体就称为该实例的原型。
图2.1
当你定义一个函数对象的时候,其内部就有这样一个链表关系。声明foo对象,自带了_proto_的属性,而这个属性指向了prototype,从而实现对象的扩展(例如继承等操作)。
图2.2
如上图所示,一个没有继承操作的函数的_proto_都会指向object.prototype,而object.prototype都会指向null。
图2.3
如上图所示,定义两个函数对象a和b,每个对象分别具有一个属性和方法。他们两个函数对象的区别是b继承了a,而继承是通过创建a的实例,并将实例赋给b.prototype实现的。实现的本质是重写原型的对象,代之以一个新的类型的实例。换句话说,原来存在于a的实例中的所有属性和方法,现在也存在于b.prototype中了。在确立了继承关系之后,我们给b.prototype添加了一个方法,这样就继承a的属性和方法的基础上又添加了一个新方法。然后继续创建一个b的实例c,这样c就具有了b的全部方法和属性,所以console的结果分别是111与222。
前端面试拓展:
图2.4
p没有b属性,会一直通过__proto__向上查找,最后当查找到object.prototype时找到,最后打印出b,向上查找过程中,得到的是object.prototype,而不是function.prototype,所以找不到a属性,所以结果为undefined,这就是原型链,通过__proto__向上进行查找,最终到null结束。最终逻辑即下图:
图2.5
三. 对象简介
对象的定义:对象是javascript的一个基本数据类型,是一种复合值,它将很多值(原始值或者其他对象)聚合在一起,可通过名字访问这些值。即属性的无序集合。
第一:javascript对象是基本数据类型之一,是复合类型;
第二:javascript中几乎所有事物都是做对象;
第三:javascript的对象是拥有属性和方法的数据;
第四:javascript 中的对象可以简单理解成"名称:值"对(name:value)。名称(name):"名称"部分是一个 javascript 字符串
图3.1
第一种创建对象方式如上图所示,直接创建一个对象,或者叫做对象直接量、字面量。
图3.2
第二种创建对象方式如上图所示,通过new.object创建对象,该方法只能创建系统自带的对象,如:new object(), array(), number(),boolean(), date()...
图3.3
第三种创建对象方式如上图所示,通过构造函数的形式创建对象,构造函数一般使用驼峰式命名方法命名。
图3.4
第四种创建对象方式如上图所示,创建一个继承该原型的实例对象。
四. 数据类型和内存图
栈:原始数据类型(undefined,null,boolean,number、string)。
堆:引用数据类型(对象、数组和函数)。
两种类型的区别是:存储位置不同。原始数据类型是直接存储在栈(stack)中的简单数据段,占据空间小、大小固定,属于被频繁使用数据,所以放入栈中存储;引用数据类型是存储在堆(heap)中的对象,占据空间大、大小不固定。如果存储在栈中,将会影响程序运行的性能;引用数据类型在栈中存储了指针,该指针指向堆中该实体的起始地址。当解释器寻找引用值时,会首先检索其在栈中的地址,取得地址后从堆中获得实体。
图4.1
五. 作用域
变量的作用域无非就是两种:全局变量和局部变量。
全局作用域:最外层函数定义的变量拥有全局作用域,即对任何内部函数来说,都是可以访问的。
局部作用域:和全局作用域相反,局部作用域一般只在固定的代码片段内可访问到,而对于函数外部是无法访问的,最常见的例如函数内部。需要注意的是,函数内部声明变量的时候,一定要使用var或者let命令。如果不用的话,你实际上声明了一个全局变量!
图5.1
只要函数内定义了一个局部变量,函数在解析的时候都会将这个变量“提前声明”。另外javascript并没有所谓的块级作用域,javascript的作用域是相对函数而言的,可以称为函数作用域:
全局函数无法查看局部函数的内部细节,但局部函数可以查看其上层的函数细节,直至全局细节。当需要从局部函数查找某一属性或方法时,如果当前作用域没有找到,就会上溯到上层作用域查找,直至全局函数。
本文参考链接:
1、https://www.cnblogs.com/libin-1/p/5911190.html
2、https://www.cnblogs.com/foodoir/p/5971686.html
3、https://github.com/markyun/my-blog/tree/master/front-end-developer-questions/questions-and-answers
推荐阅读
-
个人对JS原型链的一些理解(prototype、__proto__)
-
Js一些基础概念(持续完善……)
-
个人JS体系完善(一)
-
个人对JS原型链的一些理解(prototype、__proto__)
-
vue koa2 nuxt.js 从零开始做个人博客(一) 登录注册功能前端部分
-
javascript-有没有分享3个人后才能进入一个页面的php/asp/html&js代码
-
javascript-有没有分享3个人后才能进入一个页面的php/asp/html&js代码
-
关于js 的 match函数的一点个人理解(jquery.form.js match)
-
使用node.js搭建简易的个人博客(一)
-
个人JS体系完善(一)