高级JS
预解释
在JS中如果变量的名字和函数的名字重复了,也算冲突,在预解释中,如果名字已经声明过了,不需要在重新声明,但是需要重新赋值
如何查找上级作用域
看当前函数是在哪个作用域下定义的,那么它的上级作用域就是谁,和函数在哪执行的没有任何关系,只在它在哪里执行有关。
JS内存释放
堆内存
对象数据类型或者函数数据类型在定义的时候首先都会开辟一个堆内存,堆内存有一个引用地址,如果外面有变量等知道了这个地址,我们就说这个内存被占用了,就不能销毁了。
我们想要让堆内存释放/销毁,只需要把所有引用它的变量值赋值为null即可,如果当前的堆内存没有任何东西被占用,那么浏览器会在空闲的时候把它销毁。
var obj={name:'张三'};
obj1=null;
栈内存
//全局作用域
只有当页面关闭的时候全局作用域才会销毁;
//私有作用域 只有函数执行会产生私有作用域
一般情况下,函数执行会形成一个新的私有作用域,当私有作用域代码执行完成后,我们当前作用域都会主动的进行释放和销毁。
但是还是存在特殊的情况的:当前私有作用域中的部分内存被作用域以外的东西占用了,那么当前的这个作用域就不能销毁了。
函数关键词this
//我们在js中主要研究得都是函数中得this
//JS中得this代表得是当前行为执行得主体,JS中得context代表得是当前行为执行得环境区域
//this是谁和函数在哪定义得和在哪执行的都没有任何关系,如何区分this呢?
1 函数执行,首先看函数名前面是否有“.”,前面有点的话,点前面是谁this就是谁,没有的话this就是window。
2 自执行函数中的this永远是window
3 给元素的某一个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的this是当前元素
4在构造函数模式中类中出现的this,是指当前的实例
console.log(this);-> window
function 吃饭(){
this->张文静
}
张文静.吃饭();
~function(){
张文静.吃饭();
//这里得this仍旧指的是张文静
}();
document.getElementById("div1").onclick=fn;//fn中的this是#div
document.getElementById("div1").onclick=function(){
fn();//this指的是window
}
单例模式
//对象数据类型
//把描述同一个事物(同一个对象)的属性和方法放在一个内存空间下,起到了分组的作用,这样不同事物之间的属性即使属性名相同,相互也不会发生冲突
// -> 我们把这种分组编写代码的模式叫做单例模式。
// -> 在单例模式中我们把person1或者person2也叫做‘命名空间’
var person1={
name:'一户在',
age:18
}
var person2={
name:'一户',
age:48
}
工厂模式
把实现同一件事的相同的代码放到一个函数中,以后如果在想实现这个功能,不需要重新编写这些代码,只需要执行这个方法就行了。函数的封装 作用:低耦合高内聚,减少页面中的重复冗余代码
所有的编程语言都是面向对象的开发的 -> 类的继承、封装、多态
继承:子类继承父类中的属性和方法
多态:当前方法的多种形态,后台语言中多态只包含重载和重写
JS中不存在重载,js中存在重写,重写子类重写父类的方法
JS中有一个操作类似重载但是不是重载,我们可以根据传递参数的不一样,实现不同的功能。
单例模式
var jsperson1={
name:'zhangsan',
age:'8',
writeJs:function(){
console.log('my name is' + this.name );
}
};
var jsperson2={
name:'lisi',
age:'8',
writeJs:function(){
console.log('my name is' + this.name );
}
};
工厂模式
function createJsPerson(name,age){
var obj={};
obj.name=name;
obj.age=age;
writeJs:function(){
console.log('my name is' + this.name );
};
return obj;
}
var p1=createJsPerson('lpp',48);
构造函数
// 构造函数模式的目的就是为了创建一个自定义类,并且创建这个类的实例。
// 构造函数模式和工厂模式的区别?
// 1 执行的时候
// 普通函数执行 --->createJsPerson()
//构造函数模式 --->new CreateJsPerson() 通过new执行后,我们的createJsPerson就是一个类了
//而函数执行的返回值p1就是CreateJsPerson这个类的一个实例
//所有的类都是函数数据类型的,它通过new执行,变成了一个类,所有的实例都是对象数据类型的
// 而函数执行的返回值(p1)就是CreateJsPerson这个类的一个实例。
// 2 在函数代码执行时候的区别
//相同 : 都是形成一个私有作用域,然后 形参赋值 -> 预解释 ->代码从上到下执行(类和普通函数一样,有普通函数的属性)
// 不同:在代码执行之前,不用自己手动创建对象,浏览器会默认创建对象数据类型。
//接下来代码从上到下执行,以当前的实例为执行的主体(this代表的就是当前的实例),然后分别的把属性名和属性值赋值给当前的实例。
function CreateJsPerson(name,age){
this.name=name;
this.age=age;
this.writeJs=function(){
console.log(this.name);
};
}
var p1=new CreateJsPerson();
检测某一个实例是否属于这个类 instanceof
console.log(f1 instance of Fn);属于返回true,不属于返回false
7var f1=new Fn(); var f2=new Fn();
f1和f2都是Fn这个类的一个实例,都拥有x和getX两个属性,但是这两个属性实各自的私有属性,所有
console.log(f1.getX===f2.getX);// false
8 in:检测某一个属性是否属于这个对象 (attr in object),不管是私有属性还是公有属性,只要存在,用in来检测都是true。
hasOwnProperty:用来检测某一个属性是否为这个对象的‘私有属性’,这个方法能检测私有的属性
原型链
基于构造函数模式的原型模式解决了方法或者属性公有的问题 -> 把实例之间相同的属性和方法提取成公有的属性和方法,想让谁公有就放在Fn.prototype上即可。
//1 每一个函数数据类型(普通函数、类)都有一个天生自带的属性:prototype,并且这个属性是一个对象数据类型的值
// 2 并且在prototype上浏览器天生给它加了一个属性constructor(构造函数)属性值是当前函数(类)本身
// 每一个对象数据类型也天生自带一个属性 : proto