{ js 数据类型
- 基本数据类型:number, string , boolean, undefined, null
- 引用数据类型: {} 对象 , [ ] 数组, /**/ 正则, Date, function
本质区别: 基本数据类型是按值来操作的,而引用数据类型是按引用地址来操作的
{ js中内存的分类
栈内存:用来提供一个供js代码执行的环境 -》作用域(全局作用域,私有作用域)
堆内存: 用来存储引用数据类型的值 -》对象存储的是属性名和属性值,函数存储的是代码字符串
堆内存
对象数据类型或者函数数据类型在定义的时候,首先会开辟一个堆内存,它有一个引用的地址,有对象指向,说明被占用
让堆内存释放,只需要赋值为 null (数量等也可以),这时,堆内存没有被占用,浏览器会在空闲时把它销毁
栈内存
全局作用域(只有页面关闭才销毁)
私有的作用域(只有函数执行才会产生私有的作用域)
1)一般情况下,函数执行会形成一个新的私有的作用域,当私有作用域代码执行完成后,我们当前作用域会自动销毁
2) 特殊情况
a,当前私有作用域中部分内存被作用域外的东西占用,那么就不能销毁了
b,自执行函数中 odiv.onclick = function(){} 这个私有的作用域也不销毁
c, fn()(); 这个是不立即销毁
fn 是一个函数,其中 return function(){}
fn()(); 先执行 fn(); 返回一个函数的地址,再执行
{ 预解释
当浏览器加载html页面的时候,首先会提供一个供全局js代码执行的环境 -》全局作用域( global / window )
var num = 12;
var obj = { name: "andy", age: 23};
function fn(){
console.log('hello world');
}
console.log(fn); // 输出函数代码
console.log(fn()); // 输出当前函数执行的返回结果
//( return 后写的是什么,就返回什么,如果没有 return, 默认返回 undefined)
预解释(变量提升)
在当前的作用域中,js代码执行之前,浏览器首先会默认的把所有带var
和 function
的进行提前声明或者定义
对于带 var 和 function 关键字的在预解释的时候操作是不一样的
var
在预解释的时候,只是声明的提前
function
在预解释的时候提前的声明和定义都完成了 (函数可以在声明前执行,是因为在预解释的时候声明和定义已完成 )
预解释只发生在当前的作用域
下,例如:开始只对window下进行预解释,只有函数执行的时候才会对函数中的进行预解释
理解声明和定义 var num = 12;
声明 declare : var num; 默认值 undefined ->告诉浏览器在全局作用域中有一个 num 的变量
定义 defined : 给变量赋值 num 的值设置为12
练习题:
console.log(total); // undefined
var total = 0;
fn(100,200); // 分别为:undefined 300
function fn(num1, num2){
console.log( total); //
var total = num1 + num2;
console.log(total); //
}
console.log(total); // 0
将 fn 中 total 前的 var 去掉,结果依次为: undefined, 0, 300, 300
{ 全局变量,私有变量
如何区分私有变量和全局变量
1)在全局变量下声明的是全局变量
2)在 ‘私有作用域中声明的变量’ 和 ‘形参’ 都是私有的变量
在私有作用域中,我们代码执行的时候遇到一个变量,首先我们需要确定它是否为私有变量,如果是私有的变量,那么和外面的没有任何关系,如果不是私有的,往上级查找,一直找到 window 为止…(
作用域链
)
函数执行步骤
当函数执行的时候(让函数体中的代码执行),首先会形成一个新的私有作用域,然后按如下步骤执行
1)如果有形参,先给形参赋值
2)进行私有作用域中的预解释
3)私有作用域中的代码从上到下执行 。。。
函数形成一个新的私有的作用域保护了里面的私有变量不受外界的干扰…(外面的改变不了私有的,私有的也修改不了外面的)…-》闭包
闭包是一种机制
全局变量细节问题
在全局作用域中,带不带var
的区别
区别:有 var,可以进行预解释
num = 10; // -> 不带 var ,相当于给 window 添加了一个 num 属性名,值为 10
var
num2 = 20; // -> 不仅是给 window 添加了一个 num2 的属性名,值为20, 且给全局作用域增加了一个全局变量 num2, 值为20
在代码中,首先看是不是全局变量,再看不是不 window 的属性,第一个相当于 window.num
var total = 2;
function fn(){
console.log(total); // 2
total = 100;
}
fn(); //
console.log(total); // 100
修改一下: 将第一行 var total = 2; 去掉,结果:报错,total is not defined
直到 window 都没有声明变量,直接使用变量 xxx,报错: Uncaught ReferenceError: xxx is not defined
上面是取值,会报错,但如果是赋值,再去掉函数中的 console.log, 函数运行结果: 100
js 如果在不进行任何特殊处理的情况下,上面的代码报错,后面的不执行了(try … catch …)
{ 预解释是一种毫无节操的机制
if( !'num' in window){
var num = 23;
}
console.log(num); // undefined
var fn = function(){ // 匿名函数之函数表达式
console.log('abc');
}
// 不能在声明前 fn() 报错 fn is not a function
建议使用这种方式定义函数,如果报错,只要往上找函数
in: ‘num’ in window 判断 num 是否为 window 对象的一个属性
预解释的时候,不管条件是否成立
,都要把带 var 的进行提前的声明
预解释的时候只预解释 = 左边
的,右边的是值,不参与预解释
函数中有 return return 后面的是函数返回的值,不进行预解释
return 下面的代码会预解释
在 js 中如果变量和函数名字重复了,也算冲突,
变量与函数同名,已声明过的,不再声明,会重新赋值
var fn = 23;
var fn = function(){
console.log('abc');
}
console.log(fn); // 同名 结果是函数字符串
{ 自执行函数
不预解释,当代码执行到该位置时,定义和执行一起完成
(function(num){})(100); 不能 function(){...}() 浏览器会认为语法错误,前面要加()
+function(num){}(100);
-function(num){}(100);
~function(num){}(100);
!function(num){}(100);
{ 如何查找上级作用域链
看当前函数是在哪个作用域下定义的,那么它的上级作用域就是谁,和函数在哪执行无关
var num = 12;
function fn(){
var num = 100;
return function(){
console.log(num);
}
}
var f = fn();
f(); // 100
+function(){
var num = 1;
f();
}(); // 100
作用域练习题:
function fn(){
var i = 10;
return function (n){
console.log(n + (++i));
}
}
var f = fn();
f(10); // 21
f(20); // 32
fn()(10); // 21
fn()(20); // 31
思考题: 用闭包作用域的方法实现选项卡循环绑定事件的处理
{ this 关键字
js中的 this 代表的是当前行为执行的主体,js中的 context 代表的是当前行为执行的环境
区分 this (this是谁,和函数在哪定义的没有关系)
1.函数执行,看函数名前是否有 .(点) 有的话,是 . (点)前面的就是 this,没有的话,就是 window
function fn(){ console.log(this);}
function show(){
fn();
}
show(); // show中的fn执行 this =>window
var pp = {
sum: function(){
fn();
}
}
pp.sum(); // this => window
2.自执行函数中的 this 永远是 window
3.给元素的一个事件绑定方法,当事件触发的时候,执行对应的方法,方法中的 this是当前的元素
面试题:
var num = 20;
var obj = {
num: 30,
fn:(function(){
this.num *= 3;
num += 15;
var num = 45;
return function(){
this.num *= 4;
num += 20;
console.log(num);
}
})(num) // 这里传的是 window 中的 num,要用 obj 中的 num,要写成 obj.num
// 这里没有形成一个作用域,只是一个堆内存空间
}
var fn = obj.fn;
fn();
obj.fn();
console.log( window.num, obj.num);
综合实战题: 多种 方式
简单:
var num = 0;
btn.onclick = function(){
++num;
btn.innerHTML = num;
}
在项目中,为了防止全局变量冲突 ,一般禁止或减少使用全局变量
不使用全局变量的方法:将以上代码写到一个自执行函数中
+function(){ 写代码… }() 自己形成一个不销毁的私有作用域
btn.onclick = (function(){
var num = 0;
return function(){
++num;
btn.innerHTML = num;
}
})();
还有一种:点击取值,+1 后再赋值回去
再:可以利用自定义属性的方式 btn.count = 0; 赋值时 = ++this.count;