变量类型
常见值类型
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__
查找
原型链
作用域和闭包
作用域:一个变量的合法使用范围
- 全局作用域
- 函数作用域
- 块级作用域
自由变量
- 一个变量在当前作用域没有定义,但是被使用了
- 向上级作用域,一层一层以此寻找,直到找到为止
- 如果到全局作用域都没找到,则报错 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"));