浏览器内核
浏览器内核: 支持浏览器运行的最核心的程序
- Chrome, Safar内核i: webkit
- firefox内核: Gecko
- IE内核: Trident
- 360,搜狗等国内浏览器内核: Trident + webkit
内核模块
- 主线程:
- JS引擎模块: 负责JS程序的编译与运行
- Html,Css文档解析模块 : 负责页面文本的解析
- Dom/Css模块 : 负责Dom/Css在内存中的相关处理
- 布局和渲染模块 : 负责页面的布局和效果的绘制
- 文本 –> 对象 –> 布局 –> 渲染
- 分线程:
- 定时器模块 : 负责定时器的管理
- 网络请求模块 : 负责服务器请求(常规/Ajax)
- 事件响应模块 : 负责事件的管理
定时器 / JS线程 / 事件循环模型问题
- 定时器并不能真正保证定时执行(原因在于JS模型的运转流程)
- JS是单线程 所以定时器是在JS的主线程执行的
- JS单线程模式: 用途有关. 否则需要处理很复杂的同步问题
举个例子:
1 | 在执行异步代码的时候,如果定时器被正在执行的代码阻塞了, |
JS引擎代码
JS引擎代码的分类
Web Workers API
- 提供了js分线程的实现
- 分线程主要用来处理长时间的工作且不占用主线程的空间和时间
1 | Worker: 构造函数, 加载分线程执行的js文件 |
- 缺点:
- worker内代码不能操作DOM(更新UI)
- 不能跨域加载JS
- 不是每个浏览器都支持这个新特性
分线程设计出来是为了处理长时间的工作. 不是为了更新界面
1 | //创建Worker实例 |
对象扩展 - 属性描述符
- 对象所有的属性都具备了属性描述符
- Object.getOwnPropertyDescriptor()方法来获取一个属性的对应描述符
属性的描述符 (元属性:对象属性的属性)
- configurable:true 可配置
- enumerable:true 可枚举
- writable:true 可读写
Object.getOwnPropertyDescriptor() 获取属性对应描述符
- 第一个参数: 对象
- 第二个参数: 要获取描述符的对象属性
Object.defineProperty() 为对象新增定义或修改属性
- 第一个参数: 对象
- 第二个参数: 新定义或修改的属性名
- 第三个参数: 配置对象(value指定属性值)
- defineProperty的属性描述符的默认值都是false(可配置是否为true)
描述符之 writable
- writable决定是否可以修改属性的值,即value的值
- 当writable为false时,对应的属性的值是无法修改的
- 非严格模式下继续修改会静默失败. 反之会报错(typeError)
描述符之 configurable
- configurable 来决定属性是否可以配置
- 当configurable为false时,对应的属性是无法重新定义和无法删除的。但该对象还可以继续添加属性的。
- 不管是否为严格模式,configurable为false时进行重新定义或删除都会报错.
- window上的configurable是false.所以不能删
- 例外: configurable为false时, 只允许writable从true到false
1 | //给对象定义属性(新增) |
描述符之 enumerable
- enumerable是否支持属性出现在对象属性的遍历中(for in循环)
- 不可枚举的属性不会出现在
for..in
循环中
1 | var obj = {}; |
- obj.propertyIsEnumerable() 判断属性是否可枚举 (参数为对象属性)
- Object.keys() 获取可枚举的属性列表 (参数为对象)
- Object.getOwnPropertyNames() 获取所有属性列表 (参数为对象)
- 以上三个方法都不会遍历原型链
1 | console.log(obj.propertyIsEnumerable('b')); //false |
描述符小概念
- 属性描述符: 用来形容属性的属性.
- 数据描述符: 具有writable和value的属性描述符的属性.本质是属性
- 访问描述符: 具有set和get属性描述符的属性. 本质是属性
对象扩展 - 对象的不变性
- 注意! JS中所有方法的创建都是浅不变性的,只会影响目标对象和它的直接属性
- 深层次嵌套的影响不了,原型链中的更加影响不了
对象常量属性
- 值不可修改,不可重新定义,不可删除就是常量属性
- 常量属性跟对象无关
- configurable和writable为false就是常量属性
禁止对象扩展属性
- 调用 Object.preventExtensions(obj)
- 参数: 要求禁止扩展的对象
- 非严格模式下为对象添加新属性会静默失败.反之则会报错(typeError)
- 注意: 之前的属性还是可以进行重新定义和删除的.属性值也可修改
密封对象
- 调用 Object.seal(obj)
- 参数: 要求被密封的对象
- 密封后原有的属性不可进行重新定义和删除.但属性值可以修改
- 密封对象只针对一层.如果有嵌套对象不会受影响
1 | var obj = { |
冻结对象
- 调用 Object.freeze(obj)
- 参数: 要求被冻结的对象
- 冻结后禁止了对象扩展属性.原有属性不可重新定义和删除并且属性值也不可以修改
对象扩展 - 对象的访问描述符
- 当给属性定义get和set时,这个属性会被定义为 访问描述符
- set和get为属性描述符.可以定义方法
- 当前属性的属性值是根据一个或多个其他属性计算得来时,属性动态查找或获取时调用get方法
- 当其他属性根据当前属性值变化而变化时,监视当前属性时调用set方法 (参数传入value. set中不能有原生属性)
- set和get方法里可以处理更多的逻辑.并且给属性创造更安全的环境
1 | var obj = { |
- 当给属性定义value和writable时,这个属性会被定义为 数据描述符
- 当有访问描述符时,JS会忽略value和writable特性. 这两对无法兼容
- 因为有value和writable时属性称为数据描述符. 而有set和get时属性称为访问描述符
1 | var obj = {}; |
对象扩展 - 存在性检查
- 不能确定属性是否存在于对象中
in
操作符进行存在性检查 (会遍历原型链)- obj.hasOwnProperty(); 不会遍历原型链,只在对象中查找(参数是要确认存在性的属性名)
对象的扩展 - 对象属性的获取
前提:属性是数据描述符.且属性的writable为true
- 先从对象的直接属性去找.找不到去原型链找 (原型链包括对象的直接属性)
- 如果整条原型链上都没有就返回 undefined
1 | Foo.prototype.age = 10; |
前提: 属性是访问描述符
- 调用get方法获取
- 如果get方法没有,则返回undefined
1 | function Foo() {} |
function getElementsByClassName(parentNode,className,targetName) {
var arr = [];
//找到父节点下的指定class
var allNodes = parentNode.getElementsByTagName(targetName);
//遍历所有的节点
for(var i=0;i<allNodes.length;i++){
//每一个节点里的class中是否有className
var reg = new RegExp(“\b” + className + “\b”);
if(reg.test(allNodes[i].className)){
arr.push(allNodes[i])
}
}
return arr //直接返回出一个数组
}
1 | #### 自定义 addClass 方法 |
function addClass(node,className) {
//匹配className两边的空白字符
var reg = new RegExp(“\b” + className + “\b”);
//原来的class中没有就添加class. 有的话直接忽略
if(!reg.test(node.className)){ //属性的查找走原型链
node.className += (“ “+ className) //变量的查找 走的是作用域链
}
}
1 | #### 自定义 removeClass 方法 |
function removeClass(node,className) {
//匹配className两边的空白字符
var reg = new RegExp(“\b” + className + “\b”,”g”);
//原来的class中有就删掉 (用空白字符替换)
if(reg.test(node.className)){
node.className = node.className.replace(reg,””);
if(/^\s+$/.test(node.className)){
node.removeAttribute(“class”)
}
}else{
node.removeAttribute(“class”)
}
}
----------