类与类之间发生了is关系就是继承
解决代码复用
关键字
extends
super
/* 父类 */
class Animal{
constructor(eyes,legs,mouth){
this.eyes=eyes;
this.legs=legs;
this.mouth=mouth;
}
eat(){
console.log('我会吃饭');
}
}
let animalObj=new Animal(2,4,1);
console.log(animalObj);//{eyes: 2 ,legs: 4 ,mouth: 1}
animalObj.eat();//我会吃饭
/* 子类 */
class Dog extends Animal{
constructor(eyes,legs,mouth,name){
super(eyes,legs,mouth);//继承父类的属性,还可以创建自己的属性
this.name=name;
}
}
let dogObj=new Dog(2,4,1,'大黄');
console.log(dogObj);//{eyes: 2, legs: 4, mouth: 1, name: '大黄'}
dogObj.eat();//我会吃饭 继承父类的方法
函数高级
作用域和执行上下文
作用域 scope
变量和函数生效的范围,也叫做词法环境
产生时间是函数定义声明的时候
全局作用域产生是在代码运行时产生,打开浏览器时,关闭浏览器时失效
分类:
全局作用域
局部作用域:包含了函数、和块级{},暂时性死区
eval()作用域
执行上下文Execution Context
环境,代码当前的执行环境,又叫执行上下文环境
css中的BFC块级格式化上下文,声明独立环境
产生时间在函数调用时产生
声明周期
全局上下文
浏览器打开、node运行全局环境就产生,引擎最先进入这个环境
声明周期:窗口打开-窗口关闭。node打开-node关闭
局部上下文
声明周期:函数调用-调用完毕
先运行,EC进栈,执行完出栈,先进后出
EC三个阶段
创建
当调用函数时,过程中创建EC,然后再执行函数的代码
EC里包括(创建VO变量对象:{arguments(保存实参的伪数组),function declarations,variabes},创建Scope作用域,确定this)
激活
函数引用,变量赋值,执行代码
多个EC会购成一个执行上下文
销毁
VO变量对象Variabes Object
是EC创建阶段内部创建的一个对象,用来记录在当前作用域中所有可用的变量
VO中的属性不可访问(创建阶段),等激活成AO Active Object(激活阶段)后才能被访问使用
VO和AO是同一个对象,只是状态不同
创建VO的三个过程
1、建立arguments对象,检查函数中的参数
2、查找当前作用域中的声明式函数
在变量对象中与函数名建立一个属性,值为指向改函数所在的内存地址的引用,将函数名和函数引用存入VO
VO中已有同名的函数,就覆盖
3、查找当前作用域中var声明的变量
将变量名存入VO,初始值为undefined
如果变量名和函数名同名,则忽略变量名
2.3步就是提升的过程
1、找形参和Var声明的变量
2、赋值为undefined
3、形参和实参相统一
4、函数提升
5、执行代码
作用域链scope chain
var a = 10;
function foo() {
console.log(a);//10 全局的a
}
function fn() {
var a = 20;
foo();
}
fn();
SC是一套EC的访问规则,是由当前上下文与上层上下文中一系列变量对象组成,他保证了当前执行环境对符合访问权限的变量、函数的有序访问。
访问规则是:先访问自身EC,若无,则访问声明时所在的EC里的变量,一直到全局EC。
let a1 = 1, a2 = 2, a3 = 3;//1,2,3
function foo() {
var a3;
let a2 = 6;
console.log(a1, a2, a3);//1,6,un
var a3 = 9;
a1 = 8;
function bar(b) {
a3 = 7;
let a4 = 6;
console.log(a1, a2, a3);//8,6,7
}
bar(7);
}
foo();
console.log(a1, a2, a3);//8,2,3
console.log(a4);//未定义
垃圾回收机制
不再使用的变量
没有被引用的对象
局部变量
常见的回收方式
标记清除和引用计数
闭包 Closure
让你从内部函数访问外部函数的作用域,有权访问另一个函数作用域中的变量的函数
闭包是JS作用域的副产品。
广义:所有函数都是闭包,只要有函数,就有SC
狭义:应该被销毁的数据由于继续被引用,没有被销毁
1、函数的嵌套
2、内部函数在访问外部函数作用域
3、内部函数在自身所在作用域以外被调用
function outer(){
let number=5;
return function(){
console.log(number);
}
}
let result=outer();
result();//5
函数在创建时,就生成了闭包
闭包由函数以及声明该函数的EC组成,正常情况下该销毁的数据,由于外部还有引用,导致没有销毁,就形成了闭包
优缺点
1、延长生命周期,扩大局部变量的作用范围
2、实现变量的私有化
3、在内存中维持了一个变量,避免了变量重名,但作为常驻内存,使用不当容易造成无效内存
4、该销毁没有销毁,浪费内存,性能略低
练习
<body>
<input type="button" value="1">
<input type="button" value="2">
<input type="button" value="3">
<input type="button" value="4">
<input type="button" value="5">
<body>
<script>
let btns=document.querySelectorAll('input');
console.log(btns);
for(var i=0;i<btns.length;i++){
btns[i].addEventListener('click',function(){
console.log('heihei',i);//都输出嘿嘿5,因为变量是var声明
在循环时已经绑定好了事件,但是当我们点击触发事件时,输出i在去找,由于是var声明,存在提升,最后只有一个i,所以没次输出都是一个i为5,循环结束后还会执行一次I++
})
}
</script>
var fullname = 'john';
var obj = {
fullname: 'colin',
prop: {
fullname: 'rose',
getFullname: function () {
return this.fullname;
}
}
}
console.log(obj.prop.getFullname());//rose,这里调用时this指向是对象里面,所以是调用他的对象
var text = obj.prop.getFullname;
console.log(text());//john 直接调用函数,普通函数指向是全局