前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >js常见错误总结

js常见错误总结

原创
作者头像
IT工作者
发布2021-12-30 08:36:51
1.9K0
发布2021-12-30 08:36:51
举报
文章被收录于专栏:程序技术知识

全局对象和全局变量对象

全局对象GO

  • 是浏览器天生自带的存储属性和方法的堆,是一个对象

全局变量对象VO

  • 是我们代码创建的变量要存储的地方,是栈内存

全局执行上下文

带var

  • 带var是创建一个全局变量,存放在全局变量对象VO中
  • 基于var创建变量,会给VO和GO中各自存储一份

不带var

  • 不带var创建的不是变量,而是全局对象GO的一个属性

输出顺序

  • 先看是否为全局变量对象VO
  • 再看是否为全局对象GO

私有执行上下文

带var

  • 在私有上下文的AO变量对象中声明一个私有变量(是当前上下文的私有变量,和上下文以外没有必然联系)

不带var

  • 浏览器发现不是私有变量,则向其上级上下文中查找(scope-chain),如果上级也没有则继续查找,一直到EC全局上下文为止
  • 如果全局也没有,则给GO设置一个属性

作用域和作用域链

作用域

  • 当前函数’[[scope]]’ = 当前函数创建时候所在的上下文

作用域链

  • scopeChain : <当前EC, 函数[[scope]] >
  • 先找自己上下文的,自己没有,按照作用域链向上级作用域
  • 作用域链是在函数执行的时候形成的

函数执行步骤

  1. 创建私有上下文(有存放私有变量的变量对象AO)
  2. 进栈执行(会把全局上下文压缩到底部)
  3. 初始化作用域链scopeChain
  4. 初始化this指向
  5. 形参赋值(包含初始化arguments)
  6. 变量提升
  7. 代码执行
  8. 执行完可能会出栈(也可能不出栈)

内存的形式

堆内存

  • 释放:如果对内存用完后,手动释放赋值为null(null是空对象指针,也就是不指向任何的堆内存)
  • 不释放:如果有变量或者其他东西存储了堆内存的地址,则当前堆内存被视为占用,也就不能释放销毁

栈内存

  • 释放:全局栈内存,关掉页面的时候才会销毁。一般情况下,函数只要执行完,形成的私有栈内存就会被销毁释放掉(排除出现无限极递归,出现死循环的模式)
  • 不释放:如果当前上下文的某些内容(一般也是当前上下文中创建的堆)被上下文以外的变量或者其他事务所占用,那么当前上下文就不能出栈释放

内存释放机制

  • 查找引用方式(webkit内核):浏览器有自动回收垃圾的机制,定期间隔某段时间,把所有没有被占用的内存回收释放(这种垃圾回收机制比其他语言要完善一些)
  • 内存计数器方式(Trident内核):当前内存被其他东西引用了,则给堆计数1(累加计数),取消占用后,则减1,当减到零之后,浏览器就可以把它释放了

var与let

重复声明

  • 在当前上下文中,不管用什么方式,只要声明了这个变量,都不能基于let重复声明,会报错
  • 是否重复声明,并不是在代码执行阶段检测的,而是在词法解析的阶段检测的
  • 词法错误SyntaxError在词法解析阶段报错,当前代码不会执行
  • 语法错误ReferenceError在代码执行阶段报错,报错前的代码会执行

window属性

let声明的变量仅仅是全局变量,和GO没关系

var声明的变量即是全局变量,也相当于给GO(window)设置了一个属性,而且两者建立映射机制

暂时性死区

  • 基于typeof 检测一个没有声明过的变量,并不会报错,结果是’undefined’
  • 如果这个变量在后面会用到let声明,则前面在基于typeof检测就会报错,不能在声明之前使用

构造函数执行步骤

  1. 初始化作用域链
  2. 形参赋值
  3. 变量提升
  4. 首先会在当前上下文中,创建一个对象(这个对象就是当前类的实例) – 浏览器默认多做的事情
  5. 让当前上下文中的this指向新创建的对象 – 浏览器默认多做的事情
  6. 代码执行
  7. 代码执行完,如果没有设置return浏览器默认会把新创建的实例对象返回 – 浏览器默认多做的事情

原型和原型链

  • 每一个函数都天生具备一个属性:prototype(原型),prototype的属性值是一个对象(浏览器默认会给其开辟一个堆内存)
  • 在类的prototype原型对象中,默认存在一个内置的属性:constructor(构造函数),属性值就是当前类(函数)本身,所以类也称为构造函数
  • 每一个对象都天生具备一个属性:_proto_(原型链),属性值是当前实例(对象)所属类的prototype原型

原型链查找机制

  • 首先找自己的私有属性,私有属性有,调取的就是私有属性
  • 如果没有,默认基于__proto__原型链属性,找所属类prototype原型上的公共属性和方法
  • 如果还没有,则基于原型prototype中的__proto__继续向上找,一直找到Object.prototype为止

寄生组合式继承

  • call继承 + 另类原型继承
代码语言:javascript
复制
function Parent() {
  this.x = 100
}
Parent.prototype.getX = function getX() {
  return this.x
}
function Child() {
  Parent.call(this)
  this.y = 200
}
Child.prototype = Object.create(Parent.prototype)
Child.prototype.constructor = Child
Child.prototype.getY = function getY() {
  return this.y
}

let c1 = new Child

检测数据类型区别

typeof

  • typeof null的结果是’object’(这是浏览器的BUG,所有的值在计算中都以二进制编码存储,浏览器中把前三位000的当作对象),而null的二进制前三位是000,所以被识别为对象,但是它不是对象,它是空对象指针,是基本类型值)

instanceof

  • 当前类的原型只要出现在了实例的原型链上就返回true
  • 本身不能完成数据类型检测,只是利用它的特征(检测某个实例是否属于这个类)来完成数据检测

constructor

  • 本身不能完成数据类型检测,利用它的实例类型检测(不能重定向)

Object.prototype.toString.call()

  • 每一种数据类型的构造函数的原型上都有toString方法
  • 除了Object.prototype上的toString是返回当前实例所属类的信息(检测数据类型的),其余的都是转换字符串的
  • 对象.toString,toString方法中的this是对象实例,也就是检测他的数据类型,也就是this是谁,就是检测谁的数据类型
  • Object.prototype.toString.call(value)所以是把toString方法执行,基于call让方法中的this指向检测的数据值,这样就可以实现数据类型检测了

二叉树

先序遍历

代码语言:javascript
复制
function preOrder(node){
  if(!(node==null)){
    divList.push(node);
    preOrder(node.firstElementChild);
    preOrder(node.lastElementChild);
  }
}

中序遍历

代码语言:javascript
复制
function inOrder(node) {
  if (!(node == null)) {
    inOrder(node.firstElementChild);
    divList.push(node);
    inOrder(node.lastElementChild);
  }
}

后序遍历

代码语言:javascript
复制
function postOrder(node) {
  if (!(node == null)) {
    postOrder(node.firstElementChild);
    postOrder(node.lastElementChild);
    divList.push(node);
  }
}

检查对称二叉树

代码语言:javascript
复制
function isTreeSymmetric(t) {
    if (!t){
        return true
    }
    return isTreeEqual(t.left, t.right)
}

isTreeEqual = function(x, y) {
    if (!x && !y){
        return true
    }
    if (!x || !y){
        return false
    }
    if (x.value === y.value){
        return isTreeEqual(x.left, y.right) && isTreeEqual(x.right, y.left)
    } else {
        return false
    }
} 

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 全局对象和全局变量对象
    • 全局对象GO
      • 全局变量对象VO
      • 全局执行上下文
        • 带var
          • 不带var
            • 输出顺序
            • 私有执行上下文
              • 带var
                • 不带var
                • 作用域和作用域链
                  • 作用域
                    • 作用域链
                      • 函数执行步骤
                      • 内存的形式
                        • 堆内存
                          • 栈内存
                          • 内存释放机制
                          • var与let
                            • 重复声明
                              • window属性
                                • 暂时性死区
                                • 构造函数执行步骤
                                • 原型和原型链
                                • 原型链查找机制
                                • 寄生组合式继承
                                • 检测数据类型区别
                                  • typeof
                                    • instanceof
                                      • constructor
                                        • Object.prototype.toString.call()
                                        • 二叉树
                                          • 先序遍历
                                            • 中序遍历
                                              • 后序遍历
                                                • 检查对称二叉树
                                                领券
                                                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档