--------------------------------------------预解释----------------------------------------------------
数据类型的分类:
基本数据类型
number、string、boolean、null、undefined
引用数据类型
object:{} [] /^$/ Date
function
基本数据类型和引用数据类型的本质区别:
基本数据类型是按照值来操作的,引用数据类型是按照内存地址来操作的
思考1:
var num=12;
var obj={name:'张三',age:18};
function fn(){
console.log('i love you');
}
1、当浏览器加载HTML页面的时候,首先会提供一个供全局js代码执行的环境---->全局作用域(window)
2、按照以上思考1画图,分析。(易错点:fn存储的是一个地址,代表的是当前函数的整体)
3、预解释、变量提升
var num=12;
1>在当前的作用域中,js代码执行之前,浏览器首先会默认的把所有带var和function的进行提前的声明或者定义
声明:var num;
定义:num=12;
2>对于带var和function关键字的在预解释的时候操作还是不一样的
var -->在预解释的时候只是提前的声明
function-->在预解释的时候是声明+定义都完成了
3>预解释只发生在当前作用域当中,例如:开始只对Window下的进行预解释,只有函数执行的时候才会对函数中
的进行预解释
4、js中内容的分类
栈内存:用来提供一个供js代码执行的环境--->全局作用域
堆内存:用来存储引用数据类型的值,-->对象存储的是属性名和属性值,函数存储的是代码字符串
----------------------------------------------------作用域链-------------------------------------------------------------
如何区分私有变量和全局变量:
1、预解释的时候,在全局作用域下声明的变量是全局变量
2、在私有作用域中声明的变量(预解释的时候)和函数的形参都是私有的变量
作用域链:在私有作用域中,我们代码执行的时候遇到了一个变量,首先我们需要确定它是否为私有的变量,如果是私有的
变量,那么和外面的没有任何关系,如果不是私有的,则往当前作用域的上级作用域进行查找,如果上级作用域也没有则继续查找,一直找到window为止
当函数执行的时候,首先会形成一个新的私有的作用域,然后按照以下步骤执行:
1、如果有形参,先给形参赋值
2、进行私有作用域中的预解释
3、私有作用域中的代码从上到下执行
...
函数形成一个新的私有的作用域保护了里面的私有变量不受外界干扰,这种保护机制我们称为闭包
在全局作用域中,带var和不带var的关系?
区别:带var的可以进行预解释,所以赋值的前面执行不会报错;不带var的是不能进行预解释的,在前面会报错
关系:num2=12--->相当于给window增加了一个叫做num2的属性名,属性值是12
var num=12 相当于给全局作用域添加了一个全局变量num,不仅如此,它也相当于给window增加了一个属性名num2,属性值是12
--------------------------------------------预解释是一种毫无节操的机制---------------------------
预解释是毫无节操的一种机制
1》在预解释的时候不管条件是否成立都要把带var的进行提前声明
2》预解释的时候只预解释“=”左边的,右边的是值,不参与预解释
3》自执行函数定义的function在全局作用域下不进行预解释
4》函数体中return下面的代码虽然不执行了,但是需要预解释,return后面跟着的function 是不进行解释的
5》在js中如果变量的名字和函数的名字重复了,也算冲突
//in 判断"num"是否为window这个对象的一个属性,是返回true 不是返回false
---------------------------------------------如何查找上级作用域-------------------------------------------
如何查找当前作用域的上一级作用域?
看当前函数是在那个作用域下定义的,那么它的上级作用域就是谁,和函数在哪执行的没有任何关系
------------------------------------------关于内存的释放和作用域销毁----------------------------------
堆内存
对象数据类型或者函数数据类型在定义的时候首先会开辟一个堆内存,堆内存有一个引用地址,如果外面有变量等知道了这个地址,我们就说这个内存在占用了,就不能销毁了
var obj1={name:'张三'};
var obj2=obj1;
obj1=null;
obj2=null;
我们想让堆内存释放(垃圾回收)/销毁,只需要把所有引用它的变量值赋值为null即可,如果当前的堆内存中没有任何东西占用了,那么浏览器会在空闲的时候把它销毁
小扩展:
谷歌浏览器会每隔几毫秒会把当前的内存从头到尾看一遍,看看有没有内容有没有被占用,如果内存没有占用,就会主动清理掉
Ie 火狐通过计数器的原理,比如obj1={name:'张三'}}这个堆内存,会在浏览器的某一个位置记录当前这个堆内容有一个被占用了,计一个1,obj2=obj1,计为2(堆内存被两个占用),obj1=null,计1,obj2=null计0,内容被释放了。
Ie容易计混,所以会出现泄漏的问题,详见高程3
栈内存
1>全局作用域(浏览器天生开辟的)
当页面关闭的时候全局作用域才会销毁
2>私有作用域(只有函数执行会产生私有作用域)
一般情况下,函数执行会形成新的私有的作用域,当私有作用域中的代码执行完成后,我们的当前作用域都会主动的进行释放和销毁
但是还是存在特殊情况的:当前私有作用域中的部分内容被作用域以外的东西占用了,那么当前作用域就不能销毁了
A、函数执行返回了一个引用数据类型的值,并且在函数的外面被一个其他的东西接收了,这种情况下一般形成的私有作用域都不会被销毁
function fn(){
var num=100;
return function () {
}
}
var f=fn();
B、在一个私有的作用域中给DOM元素的事件绑定方法,一般情况下我们的私有作用域都不销毁
var odiv=document.getElementById('odiv');
~function(){
odiv.onclick= function () {
};
}();
C、下列情况属于不立即销毁-->fn返回的函数没有被其他的东西占用,但是还需要执行一次,所以暂时不销毁,当返回的值执行完成后,浏览器会在空闲的时间把它销毁了--->不立即销毁
function fn(){
var num=100;
return function () {
}
}
fn()();
//首先执行fn,返回一个小函数对应的内存地址,然后紧接着让返回小函数再执行
-----------------------------------------------this-----------------------------------------------------
this的关键字
不在函数中的this指的是window,比如:console.log(this);
我们在js中主要研究的是函数中的this。
js中的this指的是当前行为的主体。
function 吃饭(){
this---->张三
}
吃饭();
Js中context(上下文)代表的是当前执行的环境(区域)
张三在卧龙吃烤鱼 this指的是张三(当前的行为是由谁来发生的),卧龙就是上下文。
~function(){
张三.吃饭();
}();
function sum(){
张三.吃饭();
}
sum();
this指的是当前行为的主体,this是谁和函数在哪里定义的,和在哪里执行的没有任何关系,只和执行的主体有关系。
那么如何区分this呢?
1、函数执行的时候,看函数前面是否有”.”有的话,”.”前面是谁this就是谁,没有”.”this
就是window
思考:
function fn() {
console.log(this);
}
var obj = {fn: fn};
fn();
obj.fn();
function sum(){
fn();
}
sum();
2、自执行函数中的this永远是window
3、给元素某一个事件绑定方法,当事件触发的时候执行对应的方法,方法中的this是当前的元素
function fn(){
console.log(this);
}
document.getElementById('odiv').onclick= fn;
document.getElementById('odiv').onclick= function () {
fn();
};
4、在构造函数当中,类中(函数体中)出现的this.xxx=xxx中的this是当前类的一个实例
5、this的第5种情况:使用call/apply/bind来改变this的指向(优先级最高)
----------------------------------------------综合练习-----------------------------------------------------
综合练习题1:
function fn(){
var i=10;
return function (n) {
console.log(n+(++i));
}
}
var f=fn();
f(10);
f(20);
fn()(10);
fn()(20);
综合练习题2:
function fn(i){
return function (n) {
console.log(n+(i++));
}
}
var f=fn(13);
f(10);
f(20);
fn(15)(10);
fn(16)(20);
综合练习3:
var num = 20;
var obj = {
num: 30,
fn: (function (num) {
this.num *= 3;
num += 15;
console.log(num);
var num = 45;
return function () {
this.num *= 4;
num += 20;
console.log(num);
}
})(num)
};
var fn = obj.fn;
fn();
obj.fn();