# 数据类型

  • 字符串、数字、布尔、undefined、null、大整数、符号、对象
  • string、number、boolean、undefined、null、bigint、symbol、object

# 原型链

原型: 对象中固有的 __proto__ 属性,该属性指向对象的 prototype 原型属性

构造函数: 可以通过 new 来 新建一个对象 的函数

实例 通过构造函数和 new 创建出来的对象。 通过 __proto__ 指向原型,通过 constructor 指向构造函数。

原型链是由原型对象组成,每个对象都有 __proto__ 属性,指向了创建该对象的构造函数的原型,__proto__ 将对象连接起来组成了原型链。是一个用来实现继承和共享属性的有限的对象链。

  • 属性查找机制: 当查找对象的属性时,如果实例对象自身不存在该属性,则沿着原型链往上一级查找,找到时则输出,不存在时,则继续沿着原型链往上一级查找,直至最顶级的原型对象 Object.prototype,如还是没找到,则输出 undefined;

  • 属性修改机制: 只会修改实例对象本身的属性,如果不存在,则进行添加该属性,如果需要修改原型的属性时,则可以用: b.prototype.x = 2;但是这样会造成所有继承于该对象的实例的属性发生改变。

    • 对象的 hasOwnProperty() 来检查对象自身中是否含有该属性
    • 使用 in 检查对象中是否含有某个属性时,如果对象中没有但是原型链中有,也会返回 true

# this 指向

优先级: new > call、apply、bind > 对象.方法 > 直接调用

// 1. 全局上下文
fn()
this => window/global

// 2. 直接调用函数
obj.fn()
this => obj

fn.call(xx)
this => xx

fn.apply(xx)
this => xx

fn.bind(xx)
this => xx

// new+构造函数, this指向实例对象
new Fn()
this => 新的对象

// 箭头函数没有this, 因此也不能绑定。里面的this会指向当前最近的非箭头函数的this,找不到就是window
fn = ()=> {}
this => 外面的 this

// DOM事件绑定
onclick 和 addEventerListener 中 this 默认指向绑定事件的元素

# new 关键字

  1. 创建临时对象/新对象
  2. 绑定原型
  3. 指定 this = 临时对象
  4. 执行构造函数
  5. 返回临时对象

# 立即执行函数

立即执行函数:声明一个匿名函数,然后立即执行它。

(function(){alert('我是匿名函数')} ())  // 用括号把整个表达式包起来
(function(){alert('我是匿名函数')}) ()  // 用括号把函数包起来
!function(){alert('我是匿名函数')}()    // 求反,我们不在意值是多少,只想通过语法检查。

在 ES6 之前,只能通过它来「创建局部作用域」 使用 ES6 的 block + let 语法

{
  let a = '我是局部变量啦'
  console.log(a) // 能读取 a
}
console.log(a) // 找不到 a

# 闭包

闭包是指有权访问另一个函数作用域中的变量的函数

const add2 = function () {
  var count
  return function add () { // 访问了外部变量的函数
    count += 1
  }
}()

// 注意:闭包不是 count,闭包也不是 add,闭包是 count + add 组成的整体。
  • 用途:

    1. 避免污染全局环境。(因为用的是局部变量)
    2. 提供对局部变量的间接访问
    3. 维持变量,使其不被垃圾回收。
  • 缺点:闭包使用不当可能造成内存泄露

# JS 实现类

# 使用原型

function Dog(name){
  this.name = name
  this.legsNumber = 4
}

Dog.prototype.kind = '狗'

Dog.prototype.say = function(){
  console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}

Dog.prototype.run = function(){
  console.log(`${this.legsNumber}条腿跑起来。`)
}

const d1 = new Dog('啸天') // Dog 函数就是一个类
d1.say()

# 使用 class

class Dog {
  kind = '狗' // 等价于在 constructor 里写 this.kind = '狗'
  constructor(name) {
    this.name = name
    this.legsNumber = 4
  }
  say(){
    console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
  }
  run(){
    console.log(`${this.legsNumber}条腿跑起来。`)
  }
}
const d1 = new Dog('啸天')
d1.say()

# JS 实现继承

# 使用原型链

function Animal(legsNumber){
  this.legsNumber = legsNumber
}
Animal.prototype.kind = '动物'

function Dog(name){
  this.name = name
  Animal.call(this, 4) // 关键代码1
}
Dog.prototype.__proto__ = Animal.prototype // 关键代码2

Dog.prototype.kind = '狗'
Dog.prototype.say = function(){
  console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
}

const d1 = new Dog('啸天') // Dog 函数就是一个类
console.dir(d1)

禁用关键代码 2,如何解决?

var f = function(){ }
f.prototype = Animal.prototype
Dog.prototype = new f()

# 使用 class

class Animal{
  constructor(legsNumber){
    this.legsNumber = legsNumber
  }
  run(){}
}

class Dog extends Animal{
  constructor(name) {
    super(4)
    this.name = name
  }
  say(){
    console.log(`汪汪汪~ 我是${this.name},我有${this.legsNumber}条腿。`)
  }
}