早期js笔记

1. 浏览器内核

  • IE – trident
  • Chrome – webkit/blink
  • firefox – Gecko
  • Opera – presto
  • Safari – webkit

2. 数据类型

  • 原始值 (栈)
    • Number Boolean String undefined null
  • 引用值 (堆)
    • array object function
  • js中布尔值为false的六种情况 (转化为Boolean)
    • 0, ”, null, undefined, NaN,false
    • 其他都是true
  • 逗号运算符
    • (e1,e2) 返回的是e2

3. 基本语法

  • js语法错误引发当前代码块终止,但不会影响其他代码块的终止

4. 操作符 (运算符就是求结果)

  • 任何字符串相加都是字符串,从左往右,“视觉上链接”
  • NaN, Infinity –> Number 类型
  • 字符串比较的是ASCII码顺序,A->65, a->97
  • Infinity == Infinity (true), NaN == NaN (false,不等于任何东西)
  • && (e1 && e2)
    • 碰到假的直接返回那个假的表达式的结果,如果全都为真,返回最后一个表达式的结果
    • && 可以当做短路语句,当做if-else来用,e1和e2可以是语句,表达式
  • || (e1 || e2)
    • 碰到真的直接返回那个真的表达式的结果,如果全都为假,返回最后一个表达式的结果
  • for (e1;e2;e3)
    • 先执行e1,在判断e2,然后执行循环体,最后e3,当然e2不成立的时候,结束循环
  • ~ 位非操作符 (~1)
    • 将1(这里叫:原码)转二进制 = 00000001
    • 按位取反 = 11111110
    • 发现符号位(即最高位)为1(表示负数),将除符号位之外的其他数字取反 = 10000001
    • 末位加1取其补码 = 10000010
    • 转换回十进制 = -2
    • 转化数字为零的话,直接返回-1,其他的是-(X+1)
  • 优先级
    • . [] ()
    • ++ — – ~ !
    • * / %
    • + – +
    • << >> >>>
    • < <= > >= instanceof
    • == != === !==
    • &&
    • ||
    • , 多重求值

5. typeof

  • Number Boolean String Object Function undefined

6. 类型转化

  • Number (undefined) -> NaN (Number 转不了的东西都返回NaN), null ->0, Infinity – >Infinity,包括转化小数,范围比parseInt大
  • parseInt (true,false,null,undefined,NaN等) 全部转化为NaN
  • String 可以转化任何东西,但toString不能转化 undefined和null,可以接受一个参数,转化为相应的进制
    • String({}) — [object Object]
    • String(null) — null
    • String(一个函数) — 字符串的函数体
    • String([]) — ”
  • isNaN – 先做Number() 转化,然后在判断NaN
  • + 两边没有字符串就是数字相加,否则就是字符串相加
  • ++、–、+/- 先做Number() 转化
    • Number({}) NaN
    • Number([]) 0
    • {} + [] 0, {} 是代码块,执行空代码块,+是正负不是字符串连接符号
    • [] + {} ‘object Object’
  • + 加号,隐式转化 string
  • typeof(a) a 没有定义的情况下,返回undefined 只有这种情况不报错
  • 当number 参数为对象的时候,执行toPrimitive操作,toPrimitive 操作先检查是否有valueOf方法,如果它返回的不是对象值,就直接返回,如果是的话,就执行toString方法,返回toString的返回值

7. 函数

  • 函数也有length,代表函数形参的个数

8. 预编译(三部曲)

  • 通篇扫描,语法分析
  • 预编译 (函数声明整体提升,变量提升),发生函数执行的前一刻
    • 函数声明提升到最前面
    • 变量声明到前面
    • 函数声明优先级高于变量声明
    • 预编译执行过程
      • 创建AO对象(执行期上下文)
      • 找形参和变量声明,讲形参和变量作为AO属性名,值为undefined
      • 将实参和形参统一
      • 在函数体内找函数声明,赋值与函数体
    • 全局会生成GO对象
  • 解释执行

9. 作用域链条 [[scope]],函数的作用域链[[scope]]

  • [[scope]]是作用域
  • 运行期上下文,当函数执行时,会创建执行器上下文的内部对象AO,每次执行时,对应的执行器上下文都是独一无二的,当函数调用完毕的时候,执行上下文被销毁
  • 查找变量,从作用域连的顶端依次向下寻找
  • 从函数的作用域链顶端开始查找

10. 闭包

  • 但凡是内部的函数被保存到外部进行访问,一定形成闭包
  • 闭包会导致作用域链不释放 造成内存泄露 – 缺点
  • 闭包作用
    • 实现公用变量
      • 函数累加器,执行一次加一次
    • 可以做缓存 存储结果
      • 相当于全局变量存储
    • 私有变量
    • 模块化开发,防止全局变量污染

11. 立即执行函数

  • 此类函数没有声明,在一次执行后立即释放,适合做初始化工作
  • (function(){}()) – w3c, (function(){})()
  • 只有表达式才能被执行符号执行,执行符号就是()
  • 能被执行符号执行的表达式,函数名自动忽略

12. 对象

  • 对象创建方法
  • var a = {}, b = {name:1}, a[b] = 20, b会转化成字符串'[object Object]’
var obj = {} //对象字面量
var obj = new Object() //构造函数
function Student(){
    //var this = {
        //__proto__:Person.prototype
    }
    this.name = 'a';
    return {}; //不能return 123,系统会自动忽略原始值 在new的情况下
    //return this;
}

var s = new Student();

原始值是不能有属性和方法的

var num = 3;
num.len = 4;
conosle.log(num.len) //undefined
//new Number(3).len = 4; delete 相当于隐式调用了这个
//属性能能赋值,但是返回undefined

13. 原型

  • 原型是function对象的一个属性,它定义了构造函数制造出的对象的公共祖先。通过构造函数产生的对象,可以继承原型的属性和方法。原型也是对象
  • 可以提取公共属性
  • 隐式属性 __proto__
  • 对象的构造函数 constructor
  • 不能通过对象修改原型prototype,如果是引用值是可以修改的,相当于调用修改
  • 所有对象都是继承Object.prototype
    • Object.create(null) 没有原型
  • call/apply
    • 作用,改变this指向
    • 区别,参数不同
    • 任何方法都可以call
    • 借用你的方法,实现我的功能
    • test() 实际上是执行 test.call()
function Person(name){
    //this = obj
    this.name = name;
}
var obj = {};
Person.call(obj); //this = obj 改变this对象值

14. 继承

  • 原型链
  • 借用构造函数
function Person(name,sex){
    this.name = name;
    this.sex = sex;
}
function Student(name,sex,age){
    Person.call(this,name,sex);
    this.age = age;
}

var student = new Student('a','male',12);

共享模式 (共有原型)

Father.prototype.lastName = 'liu';
function Father(){
    
}
function Son(){
    
}
Son.prototype = Father.prototype;

圣杯模式

//通过中间件
function F(){}
F.prototype = Father.prototype;
Son.prototype = new F();

15. 命名空间

  • 管理变量,防止污染全局,适合模块化开发
  • in 和 hasOwnProperty 区别在于,in判断嫩不能访问到,hasOwnProperty只会判断对象本身里面的属性,不会去判断原型里面的属性
  • 每一个对象都有隐式__proto__对象属性,是原型链
  • constructor是属于原型的属性
  • instanceof
    • A instanceof B -> A对象是不是B构造函数构造出来的 (官方给的)
    • A instanceof B 看A的原型链上有没有B的原型
    • 区分 [] 和{}
      • instanceof
      • constructor
      • Object.prototype.toString.call([])

16. 数组

var arr1 = [10];
var arr2 = new Array(10); //长度为10的undefinedx10 的数组
var arr3 = new Array(1,2,3,4);//长度为4 元素1,2,3,4

改变原数组的方法(9个): https://www.jb51.net/article/141330.htm

let a = [1,2,3];
//ES5:
a.pop()/ a.shift()/ a.push()/ a.unshift()/ a.reverse()/ a.splice()/ a.sort() 
//ES6:
a.copyWithin() / a.fill
  • 不改变原数组的方法(8个):
    • ES5:join、toLocateString、toStrigin、slice、cancat、indexOf、lastIndexOf
    • ES7:includes
  • ES6 Array.of() 返回由所有参数值组成的数组
let a = Array.of(3, 11, 8); // [3,11,8]
let a = Array.of(3); // [3]

ES6 Arrar.from() 将两类对象转为真正的数组

// 1. 对象拥有length属性
let obj = {0: 'a', 1: 'b', 2:'c', length: 3};
let arr = Array.from(obj); // ['a','b','c'];
// 2. 部署了 Iterator接口的数据结构 比如:字符串、Set、NodeList对象
let arr = Array.from('hello'); // ['h','e','l','l']
let arr = Array.from(new Set(['a','b'])); // ['a','b']
  • 遍历方法(12个): js中遍历数组并不会改变原始数组的方法总共有12个:
    • ES5:forEach、every 、some、 fliter、map、reduce、reduceRight
    • ES6:find、findIndex、keys、values、entries

17. 类数组

  • 可以利用属性名模拟数组的特性
  • 可以动态增加length的长度
  • 如果强行让类数组调用push方法,则会根据length属性值的位置进行属性的扩充
  • 数组深拷贝
    • JSON.stringfy()和JSON.parse()
    • 但是这种简单粗暴的方法有其局限性。当值为undefined、function、symbol 会在转换过程中被忽略
function deepCopy(obj) {
      var result = Array.isArray(obj) ? [] : {};
      for (var key in obj) {
        if (obj.hasOwnProperty(key)) {
          if (typeof obj[key] === 'object') {
            result[key] = deepCopy(obj[key]);   //递归复制
          } else {
            result[key] = obj[key];
          }
        }
      }
      return result;
    }
var obj = {
    '0' : 'a',
    '1' : 'b',
    '2' : 'c',
    'length' : 3,
    'push' : Array.prototype.push //可选,
    'splice' : Array.prototype.splice //可选
}
//类数组的添加
//1.属性为索引 数字
//必须有length,最好有push方法

18. 错误信息 6种

  • EvalError
    • eval()的使用与定义不一致
  • RangeError
    • 数值越界
  • ReferenceError
    • 非法或者不能识别的引用数值
  • SyntaxError
    • 发生语法解析错误
  • TypeError
    • 操作数类型错误
  • URIError
    • URI处理函数使用不当

19. DOM

    • document.getElementsByTagName(‘div’)
    • document.getElementById
    • document.getElementsByName 只有部分标签可生效 (表单,表单元素,img,iframe)
    • document.getElementsByClassName,多个class可以一起 (ie8 以及以下没有该方法)
    • querySelector css选择器
      • 缺点选出来的元素不是实时的
    • querySelectorAll css选择器
      • 缺点选出来的元素不是实时的
  • nodelist
    • 节点类型
      • 元素节点
      • 属性节点
      • 文本节点
      • 注释节点
      • document
      • DocumentFragment
    • 元素节点是节点的一部分
  • Dom 树
    • document 对象的构造函数是HTMLDocument, 大的Document 是一个函数类,但是不能new
    • document -> HTMLDocument.prototype -> Document.prototype (一层一层的继承关系,形成了原型链)

20. 正则表达式

  • var reg = /abc/i
    • i 表示忽略大小写
    • g 全局匹配
    • m 多行匹配 var str = ‘aas\naa’ \n表示换行符,这样就可以匹配多行了
  • []
    • 表达式,一个方括号表达一位 (方括号里面的值表示取值的范围)
    • [^]放到表达式里面表示 非
  • ()
    • (a|b|c) 或 相当于表达式区间
  • 元字符 (相当于表达式)
    • \w === [0-9A-z_]
    • \W === [^\w]
    • \d === [0-9], \D === [^\d]
    • \s 表示空白字符 空格 换行符 换页符等
    • \b 表示单词边界 var str = /abc dfs lop/
    • \. === [^\r\n]
  • 量词 (贪婪模式,能匹配多的就匹配多的)
    • n+ === {1, }
    • n* === {0, }
    • n? === {0, 1}
    • n{x} === {x}
    • n{x,y} === {x,y}
    • n{x,} == {x,}
    • /(a)\1/ 括号子表达式 /(\w\1\1\1)/ 三次匹配子表达式里面的内容 这个能匹配出 xxxx 形式的字符串

21. 事件

  • 事件冒泡 (事件模型)
    • 结构式的嵌套元素才会冒泡 (自底向上),子元素向父元素传递
    • focus,blur,change,submit,reset,select等事件不冒泡
  • 事件捕获 (事件模型)
    • 结构式的嵌套元素才会冒泡 (自上向底),父元素向子元素传递
  • 一个元素只能存在一种事件模式,要么事件冒泡,要么事件捕获
  • 触发顺序
    • 先捕获,然后冒泡
  • 取消浏览器默认行为
    • 如 取消右键点击行为,跳转链接
      • return false,只有 body.onclick = function(){} 这种方式才有用,addEventLisoner 方式不能用
      • e.preventDefault()
      • 取消a标签的默认点击行为
  • 事件委托
    • 在父元素上加事件,通过源对象,冒泡行为解决性能问题

22.其他补充

  • console.dir() 可以显示一个对象所有的属性和方法

比较运算符原型链关系图https://www.jianshu.com/p/5c8f3d089fb7

function instanceof_(left, right){
  left = left.__proto__
  while(left !== right.prototype){
    left = left.__proto__ // 查找原型,再次while判断
    if(left === null){
      return false
    }
  }
  return true
}