--- title: js学习原理 url: 'https://yayi.site/archives/js学习原理' categories: JavaScript cover: 'https://cdn.jsdelivr.net/gh/yan-bolan/picbed/img/动漫/結城友奈は勇者である/三ノ·輪 銀.png' tags: 'javascript,学习,函数闭包,函数' abbrlink: 5b751401 date: 2020-11-06 12:19:41 updated: 2021-05-14 22:02:36 --- ### js 8 种类型 ### js 作用域提升 ---- \>持续更新( 有空就更新,没空就不更新了) # JavaScript \[toc\] --- 是基于对象的语言。 1. \`函数\`可以像对象一样使用。如作为参数,赋值给变量。作为返回值,等。 2. 函数闭包 函数的重要性。++了解函数主动维护了在函数内使用的外部的变量,则该函数为一个闭包++ 3. 作用域 不像其它语言,只能依赖函数级别,和全局变量。 4. 基于原型的面向对象,而不是java 基于类面向对象 对象,原型,函数,闭包 组成了JavaScript \> 其它的一些功能可以高效写代码 \> \> + 生成器,一次请求生成多次值的函数,不同请求也能挂起执行。 \> + Promise,让我们更好的控制 异步代码 \> ES : ECMScript 语言标准化,目录为止2020年,es6 用得多。 \> \> 用户还在用旧的浏览器,怎么办? transpilers,转换器+编译器。transformation + compiling ### 浏览器 + DOM 文档对象模型 Web 结构化的UI表现形式。最初是html 。 + 事件 事件驱动,定时器,点击,。。。。。 + 浏览器api 获取设备信息。。。 ### 实践 1. 调试 以前是alert. 现在,firefox 有firebug. chrome 有devtools 。 F12 2. 测试 使用断言函数。 3. 性能分析 \`\`\`javascript console.time("name") // 名为name的计时器。 console.timeEnd('name') \`\`\` ## 页面构建过程 1. 生命周期 2. page 构建阶段 1. html -\> dom。 2. 执行 js 会交替执行这两个步骤。 \[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-765FtiZf-1604636295301)(https://developers.google.com/web/updates/images/2018/07/page-lifecycle-api-state-event-flow.png)\] html -dom 会默认修复一些错误。如 paragraph 放在了head中。 在页面构建阶段,遇到脚本 元素会,暂停html-\>dom ,转去执行 js. js 由 js 引擎执行。js 引擎 各个浏览器不尽相同。chrome 是v8 \> 浏览器提供一些全局对象,如window 对象,有一个属性document ### 事件处理 生命周期第二部分:事件处理 单线程模型?? 所有已经生成的事件(无论是用户的还是服务器的ajax等)都在同一个事件队列中。按被检测到的顺序执行。 #### 事件是异步的。 对事件的处理,以及处理函数的调用是异步的。 #### 注册事件处理器 + 赋值某个特殊属性 + 内置addEventListener方法。 ## 函数 概念:函数是第一类对象 注意js 不是函数式编程! \> ES6 ,增加 剩余参数,与默认参数 \> \> + 回调函数在哪种情况 下会同步,或者异步 \> + 箭头函数和函数表达式的区别是什么 \> + 你为什么要在函数在使用默认 参数。 全局js 代码是在页面构建阶段执行的。其它的大多是函数。 ### 函数式不同点是什么 #### 函数是第一类对象 + 字面量创建 + 赋值给蛮,数组 或者其它属性 + 作为函数的参数传递 + 作为函数返回值 + 具有动态分配和创建的属性 ##### 函数式编程 + 把函数作为第一类对象是函数式编程(functional programming)的第一步 #### 回调函数 \`\`\`\`js function useless(ninjacallback){ return niniacallback(); } //这函数没有什么用 // 但反映了函数的一种能力,即函数作为另一个函数的参数,随后通过参数来调用该函数 \`\`\`\` js 可以在表达式出现的任意位置创建函数。 使用比较器 进行排序,数组都能sort ,可以传函数进去回调,返回一个+ - 0 三个 来调换位置,只是比较两个值时,进行回调我们的函数。 #### 函数作为对象的乐趣 你可以给函数添加属性 \`\`\`javascript var ninja={}; ninja.name="hi";//新对象加属性 var wieldsword= function(){}; wieldsword.sw='kata';//函数分配一个属性 //两种非常相似 \`\`\` 比如,某些算法,可以保存返回值,提高性能。 #### 存储函数 回调函数集合,怎么判断 里面的函数同与不同。 如一个集合,判断这个函数是重复的吗? 循环判断集合中是否已有,显然这样性能很差。 可以加上属性id 来判断 。如果,==已经有==这个属性id ,则说明已经被加入过了。就是重复了。没有的话,加上属性。 #### 自记忆函数 能够记住上次计算结果 。,结果按参数存储,别人调用取出参数。 ### 函数定义 js 中通过函数字面量 functional literal 来创建函数值。 + 函数定义 和函数表达式 function declarations function expressions + 箭头函数,也叫lambda函数 ES6的特性 myArg=\>myArg\*2 + 函数构造函数 这人不怎么用。以字符串的形式构造一个函数 \`\`\`js new Function('a','b','return a+b'); \`\`\` + 生成器函数 ES6中新增的功能。 不同于普通函数。这种函数==能够退出再重新进入== ,再进入之间保留函数内变量的值。 \`\`\`js function\* myGen(){yied 1;}; \`\`\` #### 函数声明和函数表达式 这是最原始的定义函数。 函数声明: function name(arg){}; 函数表达式: \`\`\`js var a=function(){};//作为赋值表达式的右值 myFunction(function(){});// 作为其他函数的参数。 \`\`\` 函数声明来说,函数名强制的。函数表达式来说,函数名则是可选的。 #### 立即函数 标准化调用:myFun(3); 立即调用: \*\*(function(){})\*\*(3); 为什么要加() 因为解析器要区分函数声明还是函数表达式。 #### 箭头函数 param =\> expression (()=\> a-b ) 只有一个参数的庆,括号可以省。没有参数反而不能省。 没有返回值,则默认是undefined ### 形参和 实参 argument parameter #### 剩余参数 ES6 \`\`\`\`js function multiMax(first,...remainingNumbers){ //其实对象? } \`\`\`\` #### 默认参数 \`\`\`js function performAction(action="defalut"){} //以前是三目运算符来做。现在简单 \`\`\` ### 函数调用 为什么this表示函数上下文 function 和method 之间区别 隐式函数传递,默认传递 this 和 arguments这两个参数。 #### arguments参数 是传递给函数的所有参数的集合 它不是数组。一种类数组结构。 传过去的可以多于。 #### this参数,函数上下文 当调用函数时,除了显式提供的参数外,this参数也会默认传递。 this 指的是什么,严重受到函数调用方式影响。不仅仅是定义函数的方式和位置决定。 #### 函数调用 + 作为一个函数function skulk() 。直接调用 + 作为一个方法 method ninja.skulk()。关联在一个对象上,实现面向对象 + 作 一个构造函数 constructor new Ninja() . 实例化一个新的对象 + 通过函数的apply 或者call方法 - skuli,apply(ninja) skulk,call(ninja) 1. 作为函数调用 有两种可能 上下文为this 或者 undefined 2. 作为方法调用 this 可能为 3. 作 一个构造函数 没有什么特别的。 4. apply call 你可能注意到,上面的方法主要区别是:最终作为函数上下文传递给执行函数的对象的不同。比如,对于方法而言是方法所在的对象。对于 顶级函数而言是window。构造函数是新创建对象的实例。等等。 \*\*但如果想改变上下文怎么办\*\*?好吧自己实现可能会有一些问题。 所以,使用js提供的 apply call 来。。。apply传递两个参数一个是上下文对象 和一个数组作为函数调用的参数。 #### 解决上下文问题 前面说了可以用apply 和call 来处理。 我们还可以用箭头函数绕过函数上下文。 以及bind方法 ##### 箭头函数绕过函数上下文 箭头函数作回调函数有一个特征:箭头函数没有单独的this值。this与所在的上下文相同。 ##### bind方法 ## 闭包和作用域 一个变量或方法有几种不同的作用域?这些作用域分别 是什么 如何定位 标识 符及其值 什么是可变变量? ### 理解闭包 闭包允许函数访问并操作逊外部的变量。只要变量或函数存在于声明函数时的作用域内,闭包即可使用函数能够访问这此变量或函数。 \`\`\`\`js var outervalue="aa"; function outerfun(){ assert(outervalue==="aa"); } //变量和函数 都是在全局中声明的,这一个作用域(实际就是闭包)从未消失。 \`\`\`\` \`\`\`js var outerValue="外部"; var later; //声明一个空变量,稍后使用 function outerFunction(){ var innerValue ='ninja'; function innerFun(){ //内部函数,声明这个函数时,innerValue是在内部函数作用域的 assert(outerValue==="外部","外部"); assert(innerValue==='ninja','ninja') } later = innerFun; // later是全局的,所以,调用并存储引用 } outerFunction(); later();//调用内部函数 \`\`\` 内部作用域消失后还能访问innerValue ? 你确定不是因为 用的是var 而不是let?? 只要内部函数一直存在,内部函数的闭包就一直保护该函数的作用域中的变量。  ### 使用闭包 #### 封装私有变量 原生的不支持私有变量。 es6 都有let了, 怎么感觉面向对象了。 #### 回调函数是另外一种常见使用闭包的场景 ### 通过执行上下文来跟踪代码 在 JavaScript中,代码执行的基础单元是函数。我们时刻使用函数,使用函数进行计算,使用函数更新UI,使用函数达到复用代码的目的,使用函数让我们的代码更易于理解。为了达到这个目标,第一个函数可以调用第二个函数,第二个函数可以调用第三个函数,以此类推。当发生函数调用时,程序会回到函数调用的位置。你想知道 JavaScript引擎是如何跟踪函数的执行并回到函数的位置的呢? JavaScript代码有两种类型:一种是全局代码,在所有函数外部定义;一种是函数代码,位于函数内部。 JavaScript引擎执行代码时,每一条语句既然具有两种类型的代码,那么就有两种执行上下文:全局执行上下文和函数执行都处于特定的执行上下文中。 两种上下文。二者最重要的差别是:全局执行上下文只有一个,当 JavaScript程序开始执行时就已经创建了全局上下文;而函数执行上下文是在每次调用函数时,就会创建一个新的。 注意: 了当调用函数时可通过关键字访问函数上下文。函数执行上下文,虽然也称为上下文,但完全是不一样的概念。执行上下文是内部的 JavaScript概念, JavaScript引擎使用执行上下文来跟踪函数的执行。 JavaScript基于单线程的执行模型:在某个特定的时刻只能执行特定的代码。一旦发生函数调用,当前的执行上下必须停止执行,并创建新的函数执行上下文来执行函数。当函数执行完成后,将函数执行上下文销毁,并重新回到发生调用时的执行上下文中。所以需要跟踪执行上下文---正在执行的上下文以及正在等待的上下文。最简单的跟踪方法是使用执行上下文栈(或称为调用栈) ### js 变量类型 你可以 var let const 来定义变量 1. const 不可再赋值,但可修改已存在的值。 2. var 该变量是在距离最近的函数内部或是在全局词法环境中定义。(忽略块级作用域)。 全局环境,块级环境,函数环境。 3. let 与var不同,let 直接在最近的词法环境中定义变量。 ## 生成器与promise generator and promise 生成器的主要用途是什么 js 的单线程模型,是怎么的?? promise .then .err 1. 拒绝promise 2. 链式调用promise then then.then.then .err 3. 等待多个promise 除了处理相互依赖的异步任务序列以外,对于等待多个独立的异步任务, #### async函数 前面的还书写一些样板代码,所以 需要一个async来管理所有promise的函数调用。 ## 面向对象与原型 可以在原型上增加特定属性。 原型虽然类似于class,但又不完全是。 在js 中可以通过原型实现继承。 每个对象都有原型的引用,当查找属性时,若对象本身不具有该属性,则会查找 原型上是否有该属性。 ### 对象构造与原型 var a={} function ninja(){}; ninja.prototype.swing=function(){return true;} // 对原型修改。 #### 动态特性的副作用 容易的修改属性导致了。。。 #### 构造函数实现对象原型 #### 实现继承 复制原型 #### instanceof 操作符 java中instanceof检测左边的类与右边的为是否是同一个子类。 js 中也差不多,只是使用在原型链中。 ### 使用es6中js 的class 前面的继承太麻烦了。 对于java转js的人来说不友好 。 所以模拟了class ,也就是语法糖。 实际上底层还是原型继承。 #### 静态方法 static #### 继承 extends es6之前实现继承是一件痛苦的事。 ## 控制对象的访问 理解getter 和setter js是容易修改属性的 代理:通过代理来控制访问。es6引入的。 ### getter setter \`\`\`js //之前方法 function jj(){ let a='s'; this.geta()=()=\> a; } //定义get set // 在对象字面量定义,或者在es6的class中定义 //在内置的Object.defineProperty定义。 \`\`\` ### 使用代理来访问 Proxy new Proxy 可以使用代理来记录日志。检测性能,自动填充属性。实现负数组索引。等等的用法。 问题: 性能上会有损耗。 ## 处理集合 map 与set ### 数组 ### Map 对象不等于MAP!! ### Set 集合的元素是唯一的。可以了解是怎么唯一的 es6之前只能模拟,。现在可以直接用。 #### 并集 #### 交集 #### 差集 ## 正则表达式 非常有用。 术语与操作符 精确匹配 转义 起止符号 重复出现 ==分组== 预定义字符集 精确匹配 或操作符 反向引用 ### 编译正则表达式 ### 捕获匹配的片段 #### 简单 #### 全局表达式匹配 #### 捕获的引用 #### 未捕获的分组 ### 利用函数进行替换 string.replace ## 代码模块化 js 到处都是全局变量 复杂度,。作用域 es6之后就提供了很好的特性 之前 是使用对象,闭包和立即函数来实现模块。 ### ES6模块 结合之前 的commonjs(语法简单优点)与amd(异步优点)的优点 export 与import 导入与导出功能。 默认导出 ## Dom操作 ### 避免布局抖动 修改布局 React 的虚拟Dom 。 对虚拟dom修改而不考虑布局抖动。恰当的时候react会判断实际的dom要怎么改。 这种创新的批处理方式,提高了性能 ## 历久弥新的事件 ### 事件循环 ### 计时器 settimeout setinterval 处理事件 dom代理事件:捕获与冒泡 ### 自定义事件 ## 跨浏览器开发的技巧 对es的支持 选定一种主发开发。 api 测试套件 ## es6的附加特性 ### 模板字符串 字符串加变量一起定。加反引号 ### 解构 就是从对象 数组中提取数据作为变量? ### 增强版的对象字面量 ## 测试与调试技巧 fiddler firefox的firebug f12 #### 测试用例??? ### 测试框架的基本原理 #### 断言
原创
js学习原理-js学习原理
本文采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。
评论交流
欢迎留下你的想法