# JSNote **Repository Path**: yanpingdong/jsnote ## Basic Information - **Project Name**: JSNote - **Description**: JS 相关知识笔记汇总 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2021-07-09 - **Last Updated**: 2023-09-08 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 个人理解 JS就是用来操控DOM和BOM的脚本语言,动态的改变DOM、响应DOM相关元素事件动作;获取DOM元素上的数据并与后台通讯(ajax);根据后台响应数据操控DOM,BOM。 学习一个JS框架简单的可以去了解如下几点就可以基本使用: 1. 如何渲染DOM(后台数据如何渲染到DOM中,并赋予响应行为) 2. 如何获取DOM中的数据,并与后台通讯 3. 路由如何操作,即多页面之间如何使用框架跳转。 # 著名的变量命名规则 **Camel 标记法**   首字母是小写的,接下来的字母都以大写字符开头。例如: `var myTestValue = 0;` **Pascal 标记法**   首字母是大写的,接下来的字母都以大写字符开头。例如:`var MyTestValue = 0;` **匈牙利类型标记法**   在以 Pascal 标记法命名的变量前附加一个小写字母(或小写字母序列),说明该变量的类型。例如,i 表示整数,s 表示字符串。例如:`var iMyTestValue = 0;` | 类型 |前缀|示例| |---|:---:|---:| |数组 |a |aValues| |布尔型|b |bFound| |浮点型(数字)| f |fValue| |函数 |fn |fnMethod| |整型(数字)|i|iValue| |对象 |o|oType |正则表达式|re |rePattern| |字符串|s|sValue| |变型(可以是任何类型) |v |vValue| # ECMAScript(ES) 是JS标准,规定了JS的变量写法、语法规范、支持数据类型、有那些关键字和保留字等。也就是说是一个用来统一JS语法或特性的标准。Web浏览器一般将ECMAScript做为JavaScript实现的基础。 简单地说,ECMAScript 描述了以下内容:语法、类型、语句、关键字、保留字、运算符、对象。ECMAScript 仅仅是一个描述,定义了脚本语言的所有属性、方法和对象。其他语言可以实现 ECMAScript 来作为功能的基准。 个人感觉有些像是JAVA的JDBC,JDBC只定义了每个接口功能意义,由不同的数据库商自行实现。ECMAScript定义其语法语义和特性,其它商家去实现然后可能会有扩展。如下图所示: ![](pic/ECMAScript_JavaScript_ActionScript_ScriptEase.gif) 更多详细内容可以参见: [ECMAScript 历史与实现](http://www.w3school.com.cn/js/pro_js_implement.asp) 所以JavaScript也只是ECMAScript的一个实现,但JavaScript并不是只由ECMAScript组成,而是由下面三个部分组成: 1. JavaScript 的核心 ECMAScript 描述了该语言的语法和基本对象; 2. DOM 描述了处理网页内容的方法和接口; 3. BOM 描述了与浏览器进行交互的方法和接口。 # 什么是ES6   网上标准定义:ECMAScript 6.0(以下简称 ES6)是 JavaScript 语言的下一代标准,已经在 2015 年 6 月正式发布了。它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言。   1996 年 11 月,JavaScript 的创造者 Netscape 公司,决定将 JavaScript 提交给国际标准化组织 ECMA,希望这种语言能够成为国际标准。次年ECMA组织就发布了规定浏览器脚本语言的标准,称为ECMAScript。因此可以理解为ECMAScript是JavaScript的规格,后者是其的实现。   标准委员会决定,标准在每年的 6 月份正式发布一次,作为当年的正式版本。接下来的时间,就在这个版本的基础上做改动,直到下一年的 6 月份,草案就自然变成了新一年的版本。这样一来,就不需要以前的版本号了,只要用年份标记就可以了。所以ESO的正式名称为《ECMAScript 2015 标准》(简称 ES2015)   因此,ES6 既是一个历史名词,也是一个泛指,含义是 5.1 版以后的 JavaScript 的下一代标准,涵盖了 ES2015、ES2016、ES2017 等等,而 ES2015 则是正式名称,特指该年发布的正式版本的语言标准。   *更多细节可看《ECMAScript 6 入门》 以上只是部分摘录* # JavaScript   JS,是JavaScript的缩写形式。JS可以理解成为一种用来依据事件或依据数据进行条件判断进而操作HTML DOM的脚本语言。比如增、删、隐藏、改变显示样式(即改变CSS)等操作。也可以通过与后台服务进行交互传递数据、获取数据等,并且可以依据返回数据操作HTML DOM。有如下比喻还是比较形像: > 如果把网站建设比喻成盖楼房,那么HTML就是这个楼房的钢筋水泥,CSS就是楼房的布局装饰,而JS就是楼房中大大小小无处不在的开关了。从这样的角度而言,JS就是Web开发中负责逻辑层的语言,而现如今相当火热的“用户体验”的概念,最重要的代码部分还是需要JS来编写。   从上面的比喻可以清析的知道,HTML是用来做各种布局控制,CSS用来做各种效果渲染的。**JS就是用来操控HTML和CSS。JS还会向后端发送请求获取数据,然后依据数据重新操作HTML和CSS再次渲染界面**。另外也可以通过JS操作BOM对象。   也就是说HTML+CSS只是一个静态的HTML页面,而各种交互效果比如点击响应,图片切换,后台数据交互等需要使用JS,即JS用来操作这些页面无素(DOM元素)。所以需要注意只要结构加载完的页面元素才可以获取到,这也就是为什么CSS会放在HTML BODY体头而JS放到HTML BODY尾的一个原因。**目前大部分项目会把CSS引入放到BODY 中的Head里,而JS引入放到BODY尾** ``` JavaScript web 开发人员必须学习的 3 门语言中的一门: 1. HTML 定义了网页的内容 2. CSS 描述了网页的布局 3. JavaScript 网页的行为 ``` > 如果把JS放到了HTML头,可以使用如下方式等到所有结构加载完成后再加载JS > 1. JS: window.onload=function(){},是JS的标准做法,等页面所有资源文件都加载完成后再执行 > 2. JQ:$(document).ready(function(){}),是JQuery的方式 > 3. window.addEventListenner('load', function(){}, false), 但这种方式不兼容IE 6 7 8. > 4. IE 6 7 8下 window.attachEvent('onreadystatechange',function(){}) # 常用浏览器内核   浏览器内核是JS运行环境,JS程序在其中解析并执行。常见的浏览器内核如下: - 谷歌浏览器(chrome): Webkit内核(v8引擎).*目前v8也用在 NodeJS, MongoDB, CouchDB中, safari 360 QQ UC ,安卓和IOS大部分手机浏览器都是用的该内核* - 火狐浏览器(firefox): Gecko内核 - 欧朋浏览器(opera):Presto内核 `Opera12.17及更早版本曾经采用的内核,现已停止开发并废弃,该内核在2003年的Opera7中首次被使用,该款引擎的特点就是渲染速度的优化达到了极致,然而代价是牺牲了网页的兼容性` - IE浏览器:Trident内核 > 浏览器最重要或者说核心的部分是“Rendering Engine”,可大概译为“渲染引擎”,不过我们一般习惯将之称为“浏览器内核”。负责对网页语法的解释(如标准通用标记语言HTML、JavaScript)按语法命令指示要求渲染(显示)网页。 所以,通常所谓的浏览器内核也就是浏览器所采用的渲染引擎,渲染引擎决定了浏览器如何显示网页的内容以及页面的格式信息。不同的浏览器内核对网页编写语法的解释也有不同,因此同一网页在不同的内核的浏览器里的渲染(显示)效果也可能不同,这也是网页编写者需要在不同内核的浏览器中测试网页显示效果的原因。 (见baidu百科)   直白的说内核的做用就是识别HTML CSS JS按其要求渲染绘制页面。 ## 浏览器兼容 - W3C发布的规范是开发者们总节开发者总结的产物,比如: 谷歌浏览器开发了一个新的CSS属性(border-radius)用来快速实现盒子圆角(内核会针对该CSS属性进行内核操作)。后来火狐浏览器也实现了该属性。最后慢慢在部分内核也都加入了该属性。然后W3C会将其融入到规范中。从中体现出了W3C的滞后性。 - 每个浏览器内核会自己开发一些自有的特性,其它内核可能由于其它原因也不支持。或者有的内核不按W3C实现其定义的标准。 # DOM   文档对象模型(Document Object Model,简称DOM),是 HTML 和 XML 的应用程序接口(API)。DOM 将把整个页面规划成由节点层级构成的文档。HTML 或 XML 页面的每个部分都是一个节点的衍生物。即用来表示文档中对象的标准模型就称为DOM。HTML的DOM如下图所示: ![](pic/dom.jpg)   DOM 通过创建树来表示文档,从而使开发者对文档的内容和结构具有空前的控制力。用 DOM API 可以轻松地删除、添加和替换节点。*即如何去控制HTML文档*。(更多细节参考 [DOM细节](http://www.w3school.com.cn/js/pro_js_implement.asp#DOM)) >个人理解:DOM就是一些API和属性并描述API功能和属性的作用,告诉大家那些接口功能是做什么使用后有什么效果,从属性中能拿到那些数据。让不同的开发商去实现有标准含义的接口。比如Netscape和微软,他们实现的DOM接口必需要符合W3C所定义的DOM API和属性 # BOM   浏览器对象模型(Browser Object Model,简称BOM):可以对浏览器窗口进行访问和操作。使用 BOM,开发者可以移动窗口、改变状态栏中的文本以及执行其他与页面内容不直接相关的动作。使 BOM 独树一帜且又常常令人怀疑的地方在于,它只是 JavaScript 的一个部分,没有任何相关的标准。   BOM 主要处理浏览器窗口和框架,不过通常浏览器特定的 JavaScript 扩展都被看做 BOM 的一部分。这些扩展包括: 1. 弹出新的浏览器窗口 2. 移动、关闭浏览器窗口以及调整窗口大小 3. 提供 Web 浏览器详细信息的定位对象 4. 提供用户屏幕分辨率详细信息的屏幕对象 5. 对 cookie 的支持 6. IE 扩展了 BOM,加入了 ActiveXObject 类,可以通过 JavaScript 实例化 ActiveX 对象   由于没有相关的 BOM 标准,每种浏览器都有自己的 BOM 实现。有一些事实上的标准,如具有一个窗口对象和一个导航对象,不过每种浏览器可以为这些对象或其他对象定义自己的属性和方法。 > 理解可以参见BOM的个人理解部分,两者应该一样。只是操作的对象不一样!   更多细节可参见:[BOM 细节](http://www.w3school.com.cn/js/pro_js_implement.asp#BOM) # [HTML CSS 基础](html_css/README.md) 简单说明html与css是什么。以及导入方式! # [JavaScript 数据类型](data_type/README.md) 数据类型,基本类型与引用类型的用法区别;类数组说明;数组塌陷是什么。 # [console常用调试命令](console/README.md)   本节说明了console的几大类命令,可以很方便的在控制台看输出信息,方便调试: 1. 显示命令(log,info,error,warn)和占位符(%s,%d/%i,%f,%o). 2. 信息分组(group) 3. 查看对象的信息(dir) 4. 显示某个节点的内容(dirxml) 5. 判断变量是否是真(assert) 6. 追踪函数的调用轨迹(trace) 7. 计时功能(time,timeEnd) 8. 性能分析(profile) 9. 表格显示数据(table) # URL 字符编码 URL 只能使用 ASCII 字符集. 来通过因特网进行发送。由于 URL 常常会包含 ASCII 集合之外的字符,URL 必须转换为有效的 ASCII 格式。 URL 编码使用 "%" 其后跟随两位的十六进制数来替换非 ASCII 字符。 URL 不能包含空格。URL 编码通常使用 + 来替换空格。 ``` 如果URL种有中文会转义 原始:https://www.baidu.com/s?wd=海上繁花 转译后:https://www.baidu.com/s?wd=%E6%B5%B7%E4%B8%8A%E7%B9%81%E8%8A%B1 ``` # [对象](object/README.md) CMA-262 把对象(object)定义为“属性的无序集合,每个属性存放一个原始值、对象或函数”。严格来说,这意味着对象是无特定顺序的值的数组。 尽管 ECMAScript 如此定义对象,但它更通用的定义是基于代码的名词(人、地点或事物)的表示。 # [全局作用域](globle_scope/README.md) 不声明的变量会成为全局作用域,以及其原因。 # [闭包](Closure/README.md) 闭包就是一个函数引用另外一个函数的变量,因为变量被引用着所以不会被回收,因此可以用来封装一个私有变量。这是优点也是缺点,不必要的闭包只会徒增内存消耗!另外使用闭包也要注意变量的值是否符合你的要求,因为他就像一个静态私有变量一样。 # [javascript立即执行函数](ImmediateFunctions/README.md)   简单说明什么是立即执行函数,CommonJS/AMD的方案就是使用了立即执行函数在全局window对象上挂了两个方法,一个叫require()另一个叫define()。然后模块编写者只需要在自已编写的模块中调用define()方法,把自己的模块注册进去,其它模块在依赖的时候可以使用require进行查找。 # [回调函数](callback_function/README.md) 在Javascript中,函数是第一类对象,这意味着函数可以像对象一样按照第一类管理被使用。既然函数实际上是对象:那么它们就能被“存储”在变量中,能作为函数参数被传递,能在函数中被创建,能从函数中返回。 在Javascript编程中回调函数经常以几种方式被使用,尤其是在现代web应用开发以及库和框架中: - 异步调用(例如读取文件,进行HTTP请求,等等) - 时间监听器/处理器 - setTimeout和setInterval方法 - 一般情况:精简代码 # [js的变量提升和函数提升](JSHoisting)   在ES6之前,JavaScript没有块级作用域(一对花括号{}即为一个块级作用域),只有全局作用域和函数作用域。变量提升即将变量声明提升到它所在作用域的最开始的部分。   *块,就像if语句,并不会创建一个新的作用域。只有函数才会创建新的作用域。*   [原文地址](https://www.cnblogs.com/kawask/p/6225317.html) # [判断浏览器](JudgeBrowserAndVersion/README.md) 如何判断请求的浏览器,同的浏览器中有些对象接口的使用方式是不同的或者实现一个场景的方式也是不同。但现在使用框架,基本都解决了浏览器兼容问题。 # [JS中四种类型判断方法](type_judgement/README.md) 列举四种JS类型判断方法。程序在浏览器中运行后可以直接用F12查看console页看结果。 # 两种给页面元素设置属性区别   给HTML页面元素,使用"xxx.自定义属性=vaule"和"xxx.setAttribute('自定义属性',value)"   第一种是把当前操作元素做的一个元素当做一个普通对象,为其设置一个属性名,和页面中的HTML标签没有关系,第二种是把元素当做是特殊的元素对象来做处理,设置的自定义属性是和页面结构中的DOM元素映射在一起的.   可以这样理解:setAttribute是DOM的一个操作,所以必然会影响到DOM结构,而直接"xxx.自定义属性=vaule"是js的一个语法,在JS的世界所有的东西(所以自然包括元素对像(DOM))都是对象,都可以直接用'.'的方式添加属性和方法.他们只是将属性添加到了不同位置,见后面图 ```html set attribute demo
1
``` 从下图可以看到第一种方式并没有把firstWay添加到dom上,而第二个会 ![](pic/setAttribute.png) 从下图证明第一种方式已经把属性加入了对象中,从中可以发现两种方式是将属性放入了不同的位置 ![](pic/setAttribute2.png) # '=='与'==='的主要区别   '=='进行比较的时候,如果比较的两个数据类型不一样的时候,浏览器会默认转换为相同的类型,然后再比。而'==='不会做直接进行比较。   对于引用数据类型只有空间地址相同比较才会为true。 ``` var a={}; var b=a; b==a; // true b===a; // true ```   ==进行比较两边类数据类型不一样都会先转换成数字然后再进行比较,但是null和undefined除外,即这两个值和其它任何值都不相等,但两者==为ture。 ``` []=='' // 0==0 --> true []==false //0==0 -->true null ==undefined //true ``` # &&逻辑与||逻辑或 1. 在条件判断中 &&:所有条件都为真,整体才为真 ||:只要一个条件为真,整体就为真 2. 在赋值操作中 &&: A&&B 首先看A的真假,A为假返回A的值,A为真返回B的值,遇到假立刻返回 ``` var arg = 1&&2 //=>arg=2 var arg = 0&&false //=>arg=0 ``` ||: A||B首先看A的真假,A为真返回的是A的值,A为假返回B的值(不管B是啥),遇到真立刻返回 ``` var arg = 1||2 //=>arg=1 var arg = 0||false //=>arg=false ``` ![](pic/logicOrAnd.jpg) 特别示例,|| &&混用时先算&&再算|| ``` 0||2&&false||3 1. 2&&false ==>0||false||3 2. 0||false ==> false||3 3. false||3==>3 ``` # 枚举类型 在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。 js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等 for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性,而Object.keys()只是遍历自身的可枚举属性,不可以遍历原型链上的可枚举属性. 这是for...in和Object.keys()的主要区别. 而Object.getOwnPropertyNames()则是遍历自身所有属性(不论是否是可枚举的),不包括原型链上面的. Object对象的propertyIsEnumerable()方法可以判断此对象是否包含某个属性,并且这个属性是否可枚举。需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false。 ```html

js代码输出结果在console中可见

在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。

js中基本包装类型的原型属性是不可枚举的,如Object, Array, Number等

for...in循环是 遍历对象的每一个可枚举属性,包括原型链上面的可枚举属性,而Object.keys()只是遍历自身的可枚举属性,不可以遍历原型链上的可枚举属性. 这是for...in和Object.keys()的主要区别,而Object.getOwnPropertyNames()则是遍历自身所有属性(不论是否是可枚举的),不包括原型链上面的.

Object对象的propertyIsEnumerable()方法可以判断此对象是否包含某个属性,并且这个属性是否可枚举。需要注意的是:如果判断的属性存在于Object对象的原型内,不管它是否可枚举都会返回false。

``` # 其它类型转换为Boolean 用Boolean()方法,或者 ‘!!’。JS中只有下列几个值会成为false: 0, NaN, 空字符串, null, undefined ```js Boolean(1) //true !!1 //true ``` # isNaN number变量 Number('123x') -->NaN 只有所有字符都是有效数字的时候才会是数据,否则都是NaN;另外对于引用数所类型先用toString字符串然后再转为number。 几个特殊值Number(true)为1, Number(flase)为0, Number(null)为0, Number(undefined)为NaN,Number('')为0 isNaN('123') --> false 当使用isNaN检测值的时候,检测值不是number类型时,浏览器会默认的先把值转为number类型然后再判断。 所以综合两个使用方案isNaN([])为false. 因为[].toString()为'',而Number('')为0, 0不是NaN。 一个有趣的示例: ```js NaN==NaN --> 为false typeof NaN --->(字符串)'number' ``` *注:JS与TS中的所有数值都是浮点型* # Javascript(es2016) import和require用法和区别 **这两种语法不能直接被浏览器使用** ,需要用Webpack进行转换,变为浏览器可以使用的方案。细节见 [Webpack](Webpack) 部分。 *注:export命令和import命令,都属于es6中的module体系。* ## import方式 lib.js输出一个功能如下 ```js export const sqrt = Math.sqrt; export function square(x) { return x * x; } export function diag(x, y) { return sqrt(square(x) + square(y)); } ``` 比如在yourMath.js中要使用可以通过如下引用 ```js //方法一 import { square, diag } from 'lib'; console.log(square(11)); // 121 console.log(diag(4, 3)); //方法二 import * as lib from 'lib'; square = lib.square; ``` ## require方式 其实nodejs目前也是使用这种方式创建包和引入包 Greater.js中代码如下 ```js //Greater.js module.exports = function() { var greet = document.createElement('div'); greet.textContent = "Hi there and greetings!"; return greet; }; ``` 在main.js中用require引入 ```js //main.js const greeter = require('./Greeter.js'); //和main.js在同一目录 document.querySelector("#root").appendChild(greeter()); ``` | 加载方式 |规范|命令|特点| |:---:|:---:|:---:|---:| | 运行时加载 | CommonJS/AMD | require | 社区方案,提供了服务器/浏览器的模块加载方案。非语言层面的标准。只能在运行时确定模块的依赖关系及输入/输出的变量,无法进行静态优化。| | 编译时加载 | ESMAScript6+| import | 语言规格层面支持模块功能。支持编译时静态分析,便于JS引入宏和类型检验。动态绑定。| ## import xxx from 和 import {xxx} from 区别 在导出模块的时候是否使用了export default来导出(**该方式有且只能有一个**)。如是,那么就可以使用import xxx from,否则需要使用import {xxx} from。 两个导出的区别如下: 1. export与export default均可用于导出常量、函数、文件、模块等 2. 在一个文件或模块中export、import可以有多个,但export default仅有一个 3. 通过export方式导出,在导入时要加{ },export default则不需要 4. export能直接导出变量表达式,export default不行。 # [Webpack](webpack/README.md)   简介什么是Webpack,为什么要使用Webpack,以及webpack.config.json说明。在看本节的时候需要先看 javascript立即执行函数,在解读webpack转码后的js需要知道产即执行函数的功能和写法。 # [npm 相关知识](npm/README.md) 介绍什么是npm,用npm能做什么,以及与其相关的package.json文件做用 # 函数式编程 函数式编程特征: 1. 每个函数只做一件事 2. 每个函数只返回一个结果 好处是,结果可预期,容易编写测试用例。 坏处是很容易出现横向的多层嵌套。 ```js //计算1 2 3 4相加 function add(a,b){ return a+b; } console.log(add(add(add(1,2),3),4)); ``` 一般这种情况的可以使用“链式调用解决” ```js const sum = { val_a(a){ this._a = a; return this; }, val_b(b){ this._b = b; return this; }, add(){ let _sumNum = this._a + this._b; return _sumNum; } } console.log(sum.val_a(1).val_b(2).add()) ``` # ES6解构语法 ## 带大括号入参的方法 实际上带大括号是指传递一个参数,参数类型为对象;传进来一个对象,只用到里面的几个属性,以前都是传入整个对象,然后声明变量将属性赋值给变量,或者就是直接用点,获取属性. ```js const obj={x:1,y:2,z:3} function({x,y,z}){ } // 相当于 function(obj){ var x=obj.x, y=obj.y, z=obj.z } ``` ## 三个点 三个点(...)真名叫扩展运算符,是在ES6中新增加的内容,它可以在函数调用/数组构造时,将数组表达式或者string在语法层面展开;还可以在构造字面量对象时将对象表达式按照key-value的方式展开;说白了就是把衣服脱了,不管是大括号([])、花括号({}),统统不在话下,全部脱掉脱掉!但多层嵌套的数组和对象三个点就无能为力了! ```js // 数组 var number = [1,2,3,4,5,6] console.log(...number) //1 2 3 4 5 6 //对象 var man = {name:'chuichui',height:176} console.log({...man}) / {name:'chuichui',height:176} ``` # [js写法进化](./write_mathod_process/README.md) 从一开始的最直接的HTML+CSS+JS的直观写法,发展到jQuery等基础库,再发展到类似Java、python等使用工具链管理第三方库,使用import等新语法来编写JS代码。写法的更新使得JS的开发和维护效率变的更高。 # ...扩展运算符 扩展运算符(...)是ES6的语法,用于取出参数对象的所有可遍历属性,然后拷贝到当前对象之中。 基本用法如下: ```js let person = {name: "Amy", age: 15} let someone = { ...person } someone // {name: "Amy", age: 15} //对象合并,注意后面同名的会覆盖前面的数据 let age = {age: 15} let name = {name: "Amy"} let person = {...age, ...name} person; // {age: 15, name: "Amy"} let person = {name: "Amy", age: 15}; let someone = { ...person, name: "Mike", age: 17}; someone; //{name: "Mike", age: 17} let foo = { ...['a', 'b', 'c'] }; foo // {0: "a", 1: "b", 2: "c"} ``` # new的过程 ```js function Xum(name){this.name = name;} console.log(typeof Xum) //function console.log(typeof new Xum('mm')) //object ``` Xum明明只是一个函数,可是为什么new Xum()执行后会突然返回一个对象呢? 实际上new帮我们做了这样几件事: 1. 帮我们创建了一个空对象,例如:obj; 2. 将空对象原型的内存地址__proto__指向函数的原型对象; 3. 利用函数的call方法,将原本指向window的绑定对象this指向了obj。(这样一来,当我们向函数中再传递实参时,对象的属性就会被挂载到obj上。) 4. 利用函数返回对象obj。 new的过程模拟 ```js function Xum(name){this.name = name;return this;} var obj={}; //创建了一个空对象 obj.__proto__=Xum.prototype; //空对象原型的内存地址__proto__指向函数的原型对象 var xum = Xum.call(obj, 'mm') //利用函数的call方法,将原本指向window的绑定对象this指向了obj console.log(obj); //Object { name: "mm" } 上面的创建与下面直接创建一样 abc=new Xum('mm') //Object { name: "mm" } ``` # var let const var 声明的变量在执行上下文创建阶段就会被「创建」和「初始化」,因此对于执行阶段来说,可以在声明之前使用。可以重复声明! let 声明的变量在执行上下文创建阶段只会被「创建」而不会被「初始化」,因此对于执行阶段来说,如果在其定义执行前使用,相当于使用了未被初始化的变量,会报错。所以感觉像是有了作用域。不可以重复声明! var 在全局环境声明变量,会在全局对象里新建一个属性,而 let 在全局环境声明变量,则不会在全局对象里新建一个属性。 const 与 let 很类似,都具有上面提到的 let 的特性,唯一区别就在于 const 声明的是一个只读变量,声明之后不允许改变其值。因此,const 一旦声明必须初始化,否则会报错。