JS 相关补充
JavaScript 由以下三部分组成:
- ECMAScript(核心):JavaScript 语言基础
- DOM(文档对象模型):规定了访问HTML和XML的接口
- BOM(浏览器对象模型):提供了浏览器窗口之间进行交互的对象和方法
JS内置对象
- 数据封装类对象:Object、Array、Boolean、Number、String
- 其他对象:Function、Arguments、Math、Date、RegExp、Error
- ES6新增对象:Symbol、Map、Set、Promises、Proxy、Reflect
一些规范
- 代码段使用花括号{}包裹
- 变量和函数在使用前进行声明
- 以大写字母开头命名构造函数,全大写命名常量
- 规范定义JSON对象,补全双引号
- 用{}和[]声明对象和数组
高性能编写注意
- 遵循严格模式:”use strict”;
- 将js脚本放在页面底部,加快渲染页面
- 将js脚本将脚本成组打包,减少请求
- 使用非阻塞方式下载js脚本
- 尽量使用局部变量来保存全局变量
- 尽量减少使用闭包
- 使用 window 对象属性方法时,省略 window
- 尽量减少对象成员嵌套
- 缓存 DOM 节点的访问
- 通过避免使用 eval() 和 Function() 构造器
- 给 setTimeout() 和 setInterval() 传递函数而不是字符串作为参数
- 尽量使用直接量创建对象和数组
- 最小化重绘(repaint)和回流(reflow)
最小化重绘和回流
- 需要要对元素进行复杂的操作时,可以先隐藏(display:”none”),操作完成后再显示
- 需要创建多个DOM节点时,使用DocumentFragment创建完后一次性的加入document
- 缓存Layout属性值,如:var left = elem.offsetLeft; 这样,多次使用 left 只产生一次回流
- 尽量避免用table布局(table元素一旦触发回流就会导致table里所有的其它元素回流)
- 避免使用css表达式(expression),因为每次调用都会重新计算值(包括加载页面)
- 尽量使用 css 属性简写,如:用 border 代替 border-width, border-style, border-color
变量提升
- 在JavaScript中,函数声明与变量声明经常被JavaScript引擎隐式地提升到当前作用域的顶部。
- 声明语句中的赋值部分并不会被提升,只有名称被提升
- 函数声明的优先级高于变量,如果变量名跟函数名相同且未赋值,则函数声明会覆盖变量声明
- 如果函数有多个同名参数,那么最后一个参数(即使没有定义)会覆盖前面的同名参数
原型原型链
- JavaScript的所有对象中都包含了一个 [proto] 内部属性
- 当函数对象作为构造函数创建实例时,prototype 属性值将被作为实例对象的原型 [proto]
- 当一个对象调用的属性/方法自身不存在时,就会去自己 [proto] 关联的前辈 prototype 对象上去找
- 如果没找到,就会去该 prototype 原型 [proto] 关联的前辈 prototype 去找。依次类推,直到找到属性/方法或 undefined 为止。从而形成了所谓的“原型链”
- JavaScript对象是通过引用来传递的,当修改原型时,与之相关的对象也会继承这一改变(原型特点)
this对象
- this 总是指向函数的直接调用者
- 如果有 new 关键字,this 指向 new 出来的实例对象
- 在事件中,this指向触发这个事件的对象
- IE下 attachEvent 中的this总是指向全局对象Window
DOM的发展
- DOM:文档对象模型(Document Object Model),定义了访问HTML和XML文档的标准,与编程语言及平台无关
- DOM0:提供了查询和操作Web文档的内容API。未形成标准,实现混乱。如:document.forms[‘login’]
- DOM1:W3C提出标准化的DOM,简化了对文档中任意部分的访问和操作。如:JavaScript中的Document对象
- DOM2:原来DOM基础上扩充了鼠标事件等细分模块,增加了对CSS的支持。如:getComputedStyle(elem, pseudo)
- DOM3:增加了XPath模块和加载与保存(Load and Save)模块。如:XPathEvaluator
事件委托/代理
- 是指将事件绑定目标元素的到父元素上,利用冒泡机制触发该事件
- 优点:
可以减少事件注册,节省大量内存占用; 可以将事件应用于动态添加的子元素上 - 缺点:
使用不当会造成事件在不应该触发时触发
new操作符做了什么
- 创建实例对象,this 变量引用该对象,同时还继承了构造函数的原型
- 属性和方法被加入到 this 引用的对象中
- 新创建的对象由 this 所引用,并且最后隐式的返回 this
闭包(closure)
- 闭包是指有权访问另一个函数作用域中变量的函数,创建闭包的最常见的方式就是在一个函数内创建另一个函数,通过另一个函数访问这个函数的局部变量,利用闭包可以突破作用链域
- 使用闭包主要是为了设计私有的方法和变量。闭包的优点是可以避免全局变量的污染,缺点是闭包会常驻内存,会增大内存使用量,使用不当很容易造成内存泄露。在js中,函数即闭包,只有函数才会产生作用域的概念
闭包的特性
- 函数内再嵌套函数
- 内部函数可以引用外层的参数和变量
- 参数和变量不会被垃圾回收机制回收
内存泄漏
- 内存泄漏指任何对象在您不再拥有或需要它之后仍然存在
- 垃圾回收器定期扫描对象,并计算引用了每个对象的其他对象的数量。如果一个对象的引用数量为 0(没有其他对象引用过该对象),或对该对象的惟一引用是循环的,那么该对象的内存即可回收
- setTimeout 的第一个参数使用字符串而非函数的话,会引发内存泄漏
- 闭包、控制台日志、循环(在两个对象彼此引用且彼此保留时,就会产生一个循环)
Array.slice()
- “读取”数组指定的元素,不会对原数组进行修改
- arr.slice(start, end)
Array.splice()
- “操作”数组指定的元素,会修改原数组,返回被删除的元素
- 语法:arr.splice(index, count, [insert Elements])
- index 是操作的起始位置
- count = 0 插入元素,count > 0 删除元素
- [insert Elements] 向数组新插入的元素