JS基础知识

33 阅读3分钟

变量类型

常见值类型

let a // undefined
const s = 'abc'
const n = 100
const b = true
const s = Symbol('s')

常见引用类型

const obj = { x: 100 }
const arr = ['a', 'b', 'c']
const n = null // 特殊引用类型,指针指向为空地址
function fn() {} // 特殊引用类型,但不用于存储数据,所以没有“拷贝、复制函数”这一说

typeof运算符

识别所有值类型

let a
console.log(a) // 'undefined'
const str = 'abc'
typeof str  // 'string'
const n = 100
typeof n // 'number'
const b = true
typeof b // 'boolean'
const s = Symbol('s')
typeof s // 'symbol'

识别函数

typeof console.log // 'function'
typeof function () {} // 'function'

判断是否是引用类型(不可再细分)

typeof null // 'object'
typeof ['a', 'b'] // 'object'
typeof { x: 100 } // 'object'

深拷贝

function deepClone(obj = {}) {
    if (typeof obj !== 'object' || obj == null) {
        // obj 是 null ,或者不是对象和数组,直接返回
        return obj
    }

    // 初始化返回结果
    let result
    if (obj instanceof Array) {
        result = []
    } else {
        result = {}
    }

    for (let key in obj) {
        // 保证 key 不是原型的属性
        if (obj.hasOwnProperty(key)) {
            // 递归调用!!!
            result[key] = deepClone(obj[key])
        }
    }

    // 返回结果
    return result
}

变量计算

字符串拼接

const a = 100 + 10   // 110
const b = 100 + '10' // '10010'
const c = true + '10' // 'true10'

==运算符

// == 会尝试强制类型转换
100 == '100'   // true
0 == ''  // true
0 == false // true
false == '' // true
null == undefined  // true
  • ==会尝试进行类型转换
  • 所有的地方都用===
  • 除了判断是null或者undefined时用if(obj.a == null)
const obj = { x: 100 }
if (obj.a == null) { }
// 相当于:
if (obj.a === null || obj.a === undefined) { }

原型与原型链

// 类
class People {
  constructor(name) {
    this.name = name;
  }
  eat() {
    console.log(`${this.name} eat something`);
  }
}

class Student extends People {
  constructor(name, number) {
    super(name)
    this.number = number;
  }
  sayHi() {
    console.log(
      `姓名${this.name},学号${this.number}`
    )
  }
  study() {
    console.log(
      `${this.name},学号${this.number},is studying`
    )
  }
}
class Teacher extends People {
  constructor(name, major) {
    super(name)
    this.major = major;
  }
  teach() {
    console.log(
      `${this.name},专业${this.major}is teaching`
    )
  }
}

// 通过类声明对象/实例
const xialuo = new Student("xialuo", 100);
const madongmei = new Teacher("madongmei", "science");

类型判断-instanceof

xialuo instanceof Student // true
xialuo instanceof People // true
xialuo instanceof Object // true

[] instanceof Array // true
[] instanceof Object // true

{} instanceof Object // true

// class 实际上是函数,可见是语法糖
typeof People // 'function'
typeof Student // 'function'

隐式原型和显式原型

console.log( xialuo.__proto__ )
console.log( Student.prototype )
console.log( xialuo.__proto__ === Student.prototype )

原型关系

  • 每个class都有prototype显式原型
  • 每个实例都有__proto__隐式原型
  • 实例的隐式原型,指向class的显示原型

基于原型的执行规则

  • 实例获取属性或执行方法时
  • 现在自身属性查找(可通过hasOwnProperty判断)
  • 如果找不到,就自动去__proto__查找

原型链

image.png

作用域和闭包

作用域:一个变量的合法使用范围

  • 全局作用域
  • 函数作用域
  • 块级作用域

自由变量

  • 一个变量在当前作用域没有定义,但是被使用了
  • 向上级作用域,一层一层以此寻找,直到找到为止
  • 如果到全局作用域都没找到,则报错 xx is not defined

闭包

  • 函数作为参数被传递
  • 函数作为返回值被返回
  • 隐藏数据
// 函数作为返回值
function create() {
    let a = 100
    return function () {
        console.log(a)
    }
}
let fn = create()
let a = 200
fn()

// 函数作为参数
function print(fn) {
    let a = 200
    fn()
}
let a = 100
function fn() {
    console.log(a)
}
print(fn)

// 所有的自由变量的查找,是在函数定义的地方,向上级作用域查找
// 不是在执行的地方!!!

题目

this的不同场景,怎么取值

  • 作为普通函数
  • 使用call apply bind
  • 作为对象方法被调用
  • 在class方法中调用
  • 箭头函数
// this 场景题 - 1
function fn1() {
    console.log(this)
}
fn1() // window

fn1.call({ x: 100 }) // {x: 100}

const fn2 = fn1.bind({ x: 200 })
fn2() // {x: 200}

// this 场景题 - 2
const zhangsan = {
    name: '张三',
    sayHi() {
        console.log(this)
    },
    wait() {
        setTimeout(function() {
            console.log(this)
        })
    },
    waitAgain() {
        setTimeout(() => {
            console.log(this)
        })
    }
}
zhangsan.sayHi() // this 即当前对象
zhangsan.wait() // window
zhangsan.waitAgain() // 当前对象

// this 场景题 - 2
class People {
    constructor(name) {
        this.name = name
        this.age = 20
    }
    sayHi() {
        console.log(this)
    }
}
const zhangsan = new People('张三')
zhangsan.sayHi() // zhangsan对象

手写bind函数

// 模拟 bind
Function.prototype.bind1 = function () {
    // 将参数拆解为数组
    const args = Array.prototype.slice.call(arguments)

    // 获取 this(数组第一项)
    const t = args.shift()

    // fn1.bind(...) 中的 fn1
    const self = this

    // 返回一个函数
    return function () {
        return self.apply(t, args)
    }
}

创建 10 个<a>标签,点击的时候弹出来对应的序号

let i, a
for (i = 0; i < 10; i++) {
    a = document.createElement('a')
    a.innerHTML = i + '<br>'
    a.addEventListener('click', function (e) {
        e.preventDefault()
        alert(i)
    })
    document.body.appendChild(a)
}

做一个简单的cache工具

// 闭包隐藏数据,只提供API

function createCache() {
  const data = {} // 闭包中的数据,被隐藏,不被外界访问
  return {
    set: function (k, v) {
      data[k] = v;
    },
    get: function (k) {
      return data[k]
    }
  }
}

const c = createCache();
c.set("a", 100)
console.log(c.get("a"));