首先,我们要清楚JS是一门弱类型且是动态类型的语言。

弱类型就是可以让你进行一些隐式转换,如[] == 0为true,而强类型的就不行;

动态类型就是在代码运行时才去检测类型,比如a = 3; a.push(3);结果是运行时报错,而静态类型是在编译时就会报错。

javascript 定义静态变量 js静态类型_弱类型

想深入了解的同学可以去:弱类型、强类型、动态类型、静态类型语言的区别是什么?


JS中总共有三种声明变量的方式: var , let , const

var: 不支持块级作用域,存在变量提升

console.log(a)       // undefined  变量赋值会提升,但会先为undefined,执行时才赋值
b()                 // true       函数声明会提升
var a = 3

function b() {
  console.log(true)
}

let: 支持块级作用域,暂存死区,不存在变量提升

const log = console.log.bind(console)

// 不存在变量提升
log(a)          // ReferenceError: a is not defined

let a = 3

if (true) {
  let b = 2
  // let b 暂存死区
  let b = 3   // SyntaxError: Identifier 'b' has already been declared
}

// let让if{}生成块状作用域,外面并不能引用
log(b)        // ReferenceError: b is not defined

了解let更多作用:let-MDN

const: 定义一个常量,这个常量的值不能被改变

const log = console.log.bind(console)

const TYPE = 1

TYPE = 2           // TypeError: Assignment to constant variable.

const DB_CONF = {name: 'Mysql'}

DB_CONF.name = 'Mongodb'

log(DB_CONF)      //  {name: 'Mongodb'},原因是DB_CONF指向的地址没发生变化,只是对象的内容发生变化了

JavaScript中的数据类型有:undefined, null, Boolean, Number, String, Object, Symbol

基本类型: undefined, null, Boolean, Number, String,Symbol
引用类型: Object(Array, Function, Date, RegExp)

基本类型传递的是值,而引用类型传递的是引用,我们能不能把基本类型转换为引用类型呢?

// 只拿Number举例,String也是一样的
var t = 3
var t1 = new Number(t)
log(typeof t)          // number
log(typeof t1)         // object
log(t1.valueOf())      //  3

既然基本类型可以转换为引用类型,那为什么还需要基本类型呢?

引用类型Object是需要new构造的,是会存放在内存的堆中,如果把简简单单的var t = 3 放在堆中无疑太浪费存储了,所以直接把基本类型的值存放在堆栈中,这样既节省了内存,又不用管理它的回收,因为是计算机自动回收。


谈谈JavaScript中的对象Object

计算属性

let key = 'name'

var DB = {
  [key]: 'Mysql'
}

log(DB['name'])           // Mysql

new只是一个语法糖而已

const log = console.log.bind(console)

function kclass(construct, proto) {
  return function fn(...args) {
    // 构造原型
    let obj = Object.create(proto)
    fn.prototype = proto
    obj.constructor = construct
    // 调用构造方法
    obj.constructor(...args)
    // 返回对象
    return obj
  }
}

let Animal = kclass(function (name, age) {
  this.name = name
  this.age = age
}, {
  getName () {
    return this.name
  },
  getAge () {
    return this.age
  }
})

let Dog = Animal('Dog', 3)

log(Dog.getName(), Dog.getAge())          // Dog 3

对象的浅拷贝与深拷贝

let Dog = {
  name: 'Dog',
  home: {
    province: 'a1',
    address: 'a2'
  }
}

let Cat = {
  name: 'Cat',
  home: {
    province: 'c1',
    address: 'c2'
  }
}
// 浅拷贝
Object.assign(Dog, Cat)

Cat.name = 'cat1'
Cat.home.address = 'c3'      
log(Dog)                 // Dog.home.address = 'c3' Dog里的引用对象的值也随Cat变了

--------------------------------------------------------------------------------------
// 对象深拷贝
const deepCopy = function (source, target) {
  Object.keys(target).forEach(k => {
    if (target[k] instanceof Object) {
      source[k] = source[k] || {}
      deepCopy(source[k], target[k])
    } else {
      source[k] = target[k]
    }
  })
  return source
}

const merge = function (source, ...target) {
  target.forEach(t => {
    deepCopy(source, t)
  })
  return source
  // return [source, ...target].reduce((a, b) => deepCopy(a, b))       // 第二种写法
}

merge(Dog, Cat)

Cat.name = 'cat2'
Cat.home.address = 'c4'       
log(Dog)                             // Dog.home.address 还是 c2