es5总结
一、JS三大要素
1. ECMAScript
JS核心语法,语法标准,规定了js的语法、类型、语句、关 键字、保留字、操作符以及对象等;
2. DOM(Document Object Model)文档对象模型
对原生DOM节点进行操作(对浏览器的内容进行操作);
3. BOM(Brower Object Model) 浏览器对象模型
描述了与浏览器进行交互的方法和接口,是对浏览器本身进行操作,比如可以弹出新的窗口,改变状态栏中的文本、移动、缩放和关闭浏览器等。
4. alert(要弹出的内容)普通框
prompot() 提示框
confirm() 确认框,文本区,取消,确定按钮
二、检测数据类型typeof
console.log(typeof "");//string
console.log(typeof true);//boolean
console.log(typeof null);//object
console.log(typeof undefined);//undefined
console.log(typeof []);//object
console.log(typeof function(){});//function
console.log(typeof {});//object
console.log(typeof object);//undefined
console.log(typeof 1);//number
console.log(typeof ' ');//string
三、变量提升和函数提升
1.var 变量声明提升 使用var声明得变量会提升到作用域前边
console.log(a); //undefined
var a=1;
console.log(a); //1
2.变量声明提升的特点 --> 变量提升; 可以重复声明
在es6 中的let、const(扩展):
let 不能变量提升;不可以重复声明
const 用来声明常量 常量的值不可修改,常量必须在声明得时候初始化;不可重复声明
3.函数提升
1.函数的提升会放在作用域的最顶部
2.有使用var声明的变量在函数提升之后进行变量提升
3.var声明变量和函数名重复,忽略var的值
4.函数声明
function 函数名(形参列表){
//函数体
}
a(实参) 实参数和形参是一一对应的
var 函数名 = function(形参列表){
//函数体
}
//第一种函数提升:
function test1(){
console.log('test1');
}
function test1(){
console.log('第二次test1');
}
test1();//输出结果为:第二次test1
//等价于
var a=10;
var a=20;
console.log(a);//20
//第二种:
var test2=function(){console.log("1111");};
var test2=function(){console.log("2222");};
test2();//2222
//第一个结论:变量可以重复使用、可以重复定义
//第二个结论:变量可以提升
//console.log(num);//error! 全文没有num,所以会出现报错
console.log(age);//undefined 有age,但不知道值是多少
var age=20;//变量提升
console.log(age);//20
//函数变量名的提升
console.log(print);// 全文查找print 发现它是一个函数,输出[Function print]
print();//调用函数
console.log(foo);// 全文查找print 发现它是一个值 但具体值不知道 输出undefined
//foo(); error! 此时foo不是一个函数
function print(){console.log('print');}
var foo=function(){console.log('foo');}
四、操作符
1.一元操作符
1.1递增递减操作符
var a=3;
a++; //后置加加 先打印 在自增
++a; //前置加加 先自增,再打印
console.log(a);//3
console.log(a++); //3
console.log(++a); // 5
console.log(a–); //先打印,再自减
console.log(–a); //先自减,再打印
1.2.赋值操作符
var a=3;
console.log(a); //3
1.3.加减运算符
+ 相当于调用number(),将其他数据类型转换为number类型
var a=true;
console.log(+a);//NaN
var b=undefined;
console.log(+b);NaN
var c=‘hello’;
console.log(+c);//NaN
1.4.比较操作符
== 和 ===
==比较值
===比较值和数据类型 数据类型不同,直接返回false
var num = 1;
var test = 1;
test! == num //false test与num类型相同,其值也相同,非运算肯定是false
1.5.逻辑运算符
逻辑与 同真则真 有假则假
(1) && 如果第一个操作数为假,则直接跳出该假性值,否则返回第二个操作数
假性值:NaN false undefined 0 “” null
var result=(NaN && 1);
console.log(result); //NaN
console.log(1 && 5); //5
(2) || 逻辑或 有真则真,同假才假
如果第一个操作数为假,则直接返回第二个操作数
console.log(undefined || null) ;//null
console.log(2 || 3);//2
console.log(NaN || 2);//2
(3)逻辑非
! 取反 !! 转换为布尔类型
返回true false
console.log(!10);//false
console.log(!!10); //true
console.log(!!undefined); //false
2.位运算
& |
console.log(3 & 5); //1
011 & 101 --001
console.log(3 | 5);//7
3.三目运算符
表达式?表达式一:表达式2
var result=(19>18)?“成年人”:“未成年人”
console.log(result); //成年人
if(19>18){
result=“成年人”
}else{
result=“未成年人”
}
3<5?console.log(1):console.log(2)
六、数据类型转换
1.将其他数据类型转换为boolean类型
将undefined,null,0,NaN,""==>false,其他转换为true
(1)转换方式1 !!
(2)转换方式2 Boolean()
console.log(!!2) ;//true
console.log(!!undefined);//fase
console.l og(Boolean(null));//fase
console.log(!!0);//false
console.log(!!NaN);//false
console.log(!!'');//false
console.log(!!" ");//true
2.将其他数据类型转换为string类型
tostring() //获取字符串表现形式 String() +""
注意:null,undefined没有办法调用toString()方法
(1)//如果m,n都是基本数据类型,并且其中有一个是string类型,那么进行字符串拼接操作;
console.log(a.tostring(a));//'a'
console.log(String(a));//a
console.log(a+"");
(2)m+n 如果m,n都是基本数据类型,并且都不是字符串类型,那么进行转number操作
var a=123;
console.log(123+"1"); //1231
console.log(123+1); //124
console.log(true+1); //2
如果变量是number类型,默认情况下toString()是以10进制格式返回字符串表示,通过传递参数,
可以输入二进制八进制十六进制等格式字符串值
var num=10;
console.log(num.toString());
console.log(num.toString(2));//1010
console.log(num.toString(8));//12
console.log(num.toString(10));//a
任意其他数据类型和字符串相加都会转换成字符串
console.log(typeof (true + ""));//string
3.将其他数据类型转换为number类型
(1)+a
var a=true;
console.log(+a);//1
var b=false;
console.log(+b);//0
(2)Number()包装器函数
①转换的值是其他数据类型
Number(true);//1
Number(null);//0
Number(undefined);//NaN
②转换的值是string类型
Number("123");仅包含数值 转换为数值
Number("234.1"); //234.1 解析为对应的小数
Number("+12.1"); //12.1 首位为符号位,其余为为数值,转换为对应的数值
Number("0xa"); //10 如果仅包含十六进制格式,转为为对应的十进制的值
Number("010"); //10【注意】不会当做八进制被解析,结果为10。
Number(""); // 0 空字符串被转换为0
Number("1+2.3"); // NaN 符号位出现在其他位置,解析为NaN
Number("123ac"); // NaN 包含其他字符: NaN
parseFloat("123ac");//123
parseInt(123abc);//123
七、作用域
一个变量可以使用/生效的范围,包括:全局作用域、函数作用域以及块级作用域。
(1)全局作用域指的是window;
(2)函数作用域指的是函数,它是局部作用域;
(3)块级作用域指的是有花括号的地方,比如if语句、Switch语句、while语句、for循环等,它没有局部作用域,全部都可以访问到。
八、基本类型和应用类型传参
function set(stu,num){ //这里的set num是形参
stu.age=100;
num=100;
console.log(stu,num);//使用set(obj)会出现这个结果:{name:'zs',age:100};
//stu:100 num:100
}
var obj={name:'zs',age:200};
//set(obj);
//console.log(obj.age); //100
var mm=200;
set(obj,mm);//stu=obj; num=mm; stu=A001 num=200;
console.log(obj.age,mm); //100 200
九、this
1.谁调用指向谁,单独使用this是全局
在浏览器中—window对象;
在node—global对象
this的取值与调用方式有关,一般情况下,如果使用"()“调用,那我们查看”()“前是不是函数名,如果是继续查看函数名前有没有”.",如果有"."前面的那个对象就是this,那么this指向这个对象;如果不是指向全局对象(global/window)。
2.在函数中使用this,函数的所属者默认绑定到 this 上
3.在html事件中的 this,指向了接收事件的 HTML 元素
练习:https://www.runoob.com/w3cnote/js-call-apply-bind.html
4.call apply改变this指向
.call(执行环境对象,实参列表);
.apply(执行环境对象,实参列表数组);
.bind(执行环境对象)(实参列表); 参考:https://www.runoob.com/w3cnote/js-call-apply-bind.html
十、函数调用
函数声明好之后并不会直接允许,需要进行调用才能运行。
调用方法:
1. 函数名(实参列表);
2. 函数名.call(执行环境对象,实参列表);
3. 函数名.apply(执行环境对象,实参列表数组);
call与apply的功能与区别 : 反建立函数与对象之间的关系
//函数声明
function add(a,b){
return a+b;
}
//函数表达式
var sayName=function(){
console.log(this.name); //this.name = xx.sayName
}
//文件内的全局范围内被调用
console.log(add(1,2));//3
sayName();//global.name undefined
//在对象内,对象成员
var p1={
name:'zs',
//sayName:sayName
sayName
}
p1.sayName();//zs
var p2={name:'ls'};
//p1.add(); error
//p2.sayName(); error
//执行环境对象 函数作为对象中的成员
p1.sayName();//p1做主体 zs
sayName.call(p1);//sayName做主体 zs
sayName.apply(p1);//zs
//p2.sayName(); error!
sayName.call(p2);//ls
sayName.apply(p2);//ls
name='ww';
sayName.call(this);//global 相当于 this.sayName();//global
//此时的这个this 如果全局没有定义,则为undefined 有的话就是那个name值 即ww
十一、函数的应用
//1.参数的应用:对象成员去赋值
//构造函数:Bird name/color/eat/fly
function Bird(name,color,feat,ffly){
//函数的传值传得是地址值
this.name=name;
this.color=color;
this.eat=feat;
this.fly=ffly;
}
function fly(){
console.log("I can fly");
}
var b1=new Bird('boli','red',function(){console.log('妈妈喂饭')},fly);
//1.参数的应用:绑定监听函数
//button.addEventLinstner('click',function(){弹出模态框}) //addEventLinstner系统定义的
function bind(str,fn){
if(str=='click'){
console.log("浏览器与DOM节点this、事件的捕获:鼠标单击操作");
}else if(str="mouseover"){ //事件类型
console.log("浏览器与DOM节点this、事件的捕获:鼠标移入操作");
}else if(str="mouseout"){
console.log("浏览器与DOM节点this、事件的捕获:鼠标移出操作");
}else{
return ;
}
fn();
}
var button={bind};
button.bind('click',function(){console.log('弹出模态框');});
//2.作为返回值
function foo(){
return function(){
console.log('匿名函数');
}
}
function boo(){
var sayName=function(){
console.log(this.name);
}
return sayName;
}
var f=foo();
var b=boo();
f();//匿名函数
foo()();//匿名函数
b();//cundefined
boo()();//undefined
十二、对对象属性进行增删改
//1.新增删除:只能删除对象的自有属性
delete obj[“proname”]
delete obj.sayName //从obj对象中删除sayName属性
//2.新增
obj.newproname=”value”
//3.修改
可以直接点表示法覆盖
十三、内存图(栈、堆、方法区)
1.定义
栈—先进后出
堆—在堆中存放的变量位置是不确定的
2.存储过程
对于基本数据类型来说,栈中可以直接操作保存在变量中的实际值。
对于引用数据类型来说,新建一个引用数据类型变量后,就会开辟新的内存空间,但栈中存放的是变量的指针,指针指向堆中的内存地址,根据内存地址存放对应内容。
3.栈空间与堆空间
(1)栈空间: 方法调用时保存变量对象的引用或变量实例.
(2)堆空间:所有存活的对象在此分配。
4.栈内存与堆内存
(1)栈内存
在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配。当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间,当超过变量的作用域后,java会自动释放掉为该变量分配的内存空间,该内存空间可以立刻被另作他用。
(2)堆内存
栈中存放的是指针,有了指针后去堆中找对应的内存空间地址。
堆内存用于存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理。在堆中产生了一个数组或者对象后,还可以在栈中定义一个特殊的变量,这个变量的取值等于数组或者对象在堆内存中的首地址,在栈中的这个特殊的变量就变成了数组或者对象的引用变量,以后就可以在程序中使用栈内存中的引用变量来访问堆中的数组或者对象,引用变量相当于为数组或者对象起的一个别名。
参考内存图详解:https://www.cnblogs.com/cxying93/p/6106469.html
十四、闭包
1.闭包的定义
函数内部包裹函数,作用域链得不到释放,造成消耗内存。
在js作用域环境中访问变量的权利是由内向外的,内部作用域可以获得当前作用域下的变量并且可以获得包含当前作用域的外层作用域下的变量,反之则不能,也就是说在外层作用域下无法获取内层作用域下的变量,同样在不同的函数作用域中也是不能相互访问彼此变量的,那么我们想在一个函数内部也有权限访问另一个函数内部的变量该怎么办呢?闭包就是用来解决这一需求的,闭包的本质就是在一个函数内部创建另一个函数。
缺点:作用域链得不到释放,造成消耗内存。
优点:
①保护函数内的变量安全 ,实现封装,防止变量流入其他环境发生命名冲突
②在内存中维持一个变量,可以做缓存(但使用多了同时也是一项缺点,消耗内存)。
③匿名自执行函数可以减少内存消耗。(function(){ }){ }
坏处:
①被引用的私有变量不能被销毁,增大了内存消耗,造成内存泄漏,解决方法是可以在使用完变量后手动为它赋值为null;
②其次由于闭包涉及跨域访问,所以会导致性能损失,我们可以通过把跨作用域变量存储在局部变量中,然后直接访问局部变量,来减轻对执行速度的影响
解决方法:立即执行函数(IIFE),创建函数后就立即执行
立即执行函数的特点:
页面加载完成后只执行一次的设置函数,并且立马执行,执行完后立即销毁。
将设置函数中的变量包裹在局部作用域中,不会泄露成全局变量。
十五、构造函数、实例、原型对象
1.每创建一个函数,该函数都会自动带有一个prototype属性。该属性是一个指针,指向一个对象,该对象称之为原型对象(后期我们可以使用这个原型对象帮助我们在js中实现继承).
2.原型对象上默认有一个属性constructor,该属性也是一个指针,指向其相关联的构造函数。
3.Js中new一个构造函数时,通过调用构造函数产生的实例对象,都拥有一个内部属性,指向了原型对象。其实例对象能够访问原型对象上的所有属性和方法。
参考网址:https://www.cnblogs.com/liyusmile/p/8820443.html
十六、形参、实参以及构造函数
function Cat(name){
//想要猫有不同的名字,也就是this.name=xxx; 这里就用到了形参/实参/函数的参数列表
//在生孩子的同时进行赋值操作
//this.name=arguments['0']; 参数列表(方法一)
this.name=name;//(方法二,给它个形参对应实参)
}
var c1=new Cat('小花');//c1.name='小花'
var c2=new Cat('小白');//c2.name='小白'
console.log(c1,c2);
c1把所有的可枚举的属性都能返回成字符串
c1.age=2;
c1.price=200;
//c1新增toString:c1所有的可枚举的属性都能返回成字符串
c1.toString = function(){
//return this.name
//this-->c1
var str="";//默认值
for(var key in this){
var value=this[key];
str += value;
}
return str;//return value---逻辑不对
}
console.log(c1.toString());
//c2想用c1的toString函数
console.log(c2.toString());//内部没有 执行他爷爷的 [object Object]
console.log(c1.toString.apply(c2));//小白 反建立函数