# 数据类型
- 字符串、数字、布尔、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 关键字
- 创建临时对象/新对象
- 绑定原型
- 指定 this = 临时对象
- 执行构造函数
- 返回临时对象
# 立即执行函数
立即执行函数:声明一个匿名函数,然后立即执行它。
(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 组成的整体。
用途:
- 避免污染全局环境。(因为用的是局部变量)
- 提供对局部变量的间接访问
- 维持变量,使其不被垃圾回收。
缺点:闭包使用不当可能造成内存泄露
# 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}条腿。`)
}
}
← JS进阶 HTML、CSS、DOM →