上一篇:19.JS基础(五)
一、变量
1. 变量的定义
定义:值可以被修改的量叫做变量,就是存储数据的容器,本质上是内存空间
var a = 5;
var b = 10;
var a = 5,b = 10;
var a = b = 10;
var a = 10;
b = 10;
a = b;
面试题:属性的赋值优先级比变量高(连等的情况下)
var a = {n:1};
var b = a;
// a = b = 1;
// 属性的赋值优先级比变量高(连等的情况下)
// a.x = {n:2}
// a = a.x
// a = a.x = {n:2};
a.x = a = {n:2};
console.log(a.x); //undefineda
console.log(b.x); //{n:2}
2. 变量的数据类型
-
基本(值)类型
-
Number: 任意数值
-
String: 任意文本
-
Boolean: true/false
-
undefined: undefined
-
null: null
-
symbol es6
var s1 = Symbol();//对象,直接调用
-
-
对象(引用)类型
- Object: 任意对象
- Array: 一种特别的对象类型(下标/内部数据有序)
- Function: 一种特别的对象类型(可执行)
- 备注:准确来说Array和Function属于一种特别的Object类型。
3. 数据的存储
- 基本数据存储 数据本身 栈
- 对象数据存储 地址值 堆
- 备注:内存当中存储的都是值,一个存的是数据本身,另一个存的是数据所在的内存(堆结构)地址;
var a
a = 'abcdefg' // a内存中保存的是基本类型数据
a = {}// a内存中保存的是地址值
var b = true
a = b // a内存中保存的是基本类型数据
b = []
a = b // a内存中保存的是地址值
4. 判断变量的数据类型
-
typeof
typeof可以识别出基本类型String,、Number、Boolean、Undefined、Symbol,但是不能识别null。不能识别引用数据类型,会把null、array、object统一归为object类型,但是可以识别出function。
所以typeof可以用来识别一些基本类型
<script> var bool = true; var num = 1; var str = 'abc'; var und= undefined; var nul = null; var s1 = Symbol(); console.log(typeof bool); //boolean console.log(typeof num);//number console.log(typeof str);//string console.log(typeof und);//undefined console.log(typeof nul);//object console.log(typeof s1); //symbol </script>
-
instanceof
instanceof不能识别出基本的数据类型 String,、Number、Boolean、Undefined、Null、Symbol
但是可以检测出引用类型,如array、object、function,同时对于是使用new声明的类型,它还可以检测出多层继承关系。
判断某对象是否是某类
其实也很好理解,js的继承都是采用原型链来继承的。比如Dog instanceof Animal ,其实就是看objA的原型链上是否有A的原型,而A的原型上保留A的constructor属性。
所以instanceof一般用来检测对象类型,以及继承关系.
格式:console.log(变量名 instanceof 类型)
<script> var bool = true; var num = 1; var str = 'abc'; var und= undefined; var nul = null; var s1 = Symbol(); console.log(bool instanceof Boolean);// false console.log(num instanceof Number);// false console.log(str instanceof String);// false console.log(und instanceof Object);// false console.log(nul instanceof Object);// false console.log(s1 instanceof Symbol);// false console.log([] instanceof Array);//true 数组 console.log(/^$/ instanceof RegExp);//true 正则 console.log([] instanceof Object);//true 对象 </script>
-
constructor
由于null、undefined没有construstor方法,因此constructor不能判断undefined和null。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var bool = true; var num = 1; var str = 'abc'; var und= undefined; var nul = null; var s1 = Symbol(); console.log(bool.constructor === Boolean);// true console.log(num.constructor === Number);// true console.log(str.constructor === String);// true console.log(s1.constructor === Symbol);//true </script> </body> </html>
-
toString
此方法可以相对较全的判断js的数据类型。
格式: console.log(Object.prototype.toString.call(变量名));
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <script> var bool = true; var num = 1; var str = 'abc'; var und= undefined; var nul = null; var s1 = Symbol(); console.log(Object.prototype.toString.call(bool));//[object Boolean] console.log(Object.prototype.toString.call(num));//[object Number] console.log(Object.prototype.toString.call(str));//[object String] console.log(Object.prototype.toString.call(und));//[object Undefined] console.log(Object.prototype.toString.call(nul));//[object Null] console.log(Object.prototype.toString.call(s1)); //[object Symbol] </script> </body> </html>
-
总结:至于在项目中使用哪个判断,还是要看使用场景,具体的选择,一般基本的类型可以选择typeof,引用类型可以使用instanceof。
5. 面试题讲解
-
var b1 = { b2:[2,'atguigu',console.log], b3:function () { alert('hello') } } console.log(b1,b1.b2,b1.b3) //{...} [2,...] function(){...} console.log(b1 instanceof Object,typeof b1) //true object console.log(b1.b2 instanceof Array,typeof b1.b2) //true object console.log(b1.b3 instanceof Function,typeof b1.b3) //true function console.log(typeof b1.b2[2]) //function console.log(typeof b1.b2[2]('atguigu')) // atguigu
如果方法的使用上 没有添加() 那么获取的是方法体
当我们获取方法体之后 在后面添加一个()的话 那就执行了方法
-
undefined与null的区别?
- undefined代表定义变量没有赋值 var a;
- null代表赋值了, 只是值为null var a = null;
-
什么时候给变量赋值为null呢?
- 对象初始化 var obj = null;
- 删除对象 obj = null ==》 obj变为垃圾对象
-
严格区别变量类型与数据类型?(js中了解)
- 在c/java语言当中 变量也是有类型的 int a = 10; char a = ‘b’ float a = 1.3;
- 在js当中,变量类型是弱类型, 只有在数据确定存储之后,变量类型才确定 而且可以改变;(根据存储数据类型的不同而不同);
- var a = ‘老马’;
- a = 10;
- 变量的类型是变量前面的var 是根据数据类型来确定的,数据类型是等号右边数据的类型
-
2个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 另一个引用变量也看得见
var arr1 = [1,2,3]; var arr2 = arr1; arr1[1] = 22; console.log(arr2); //[1,22,3]
-
2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
var obj1 = {}; var obj2 = obj1; obj2 = {}; obj2.name = 'zs'; console.log(obj1);//{}
-
传基本数据值
var a = 10; var b = 20; function add(a,b){ a = 20; return a + b; } add(a,b); console.log(a); //10
-
传引用数据值
var arr = [1,2,3]; function fn(arr){ arr[1] = 22; } fn(arr); console.log(arr); //[1,22,3]
-
关于内存释放(堆结构)的问题
obj = null;
垃圾回收机制:堆结构当中的对象数据,要想被回收释放,必须成为垃圾对象,也就是没有人再指向这个对象数据;
二、对象
1. 什么是对象?
代表现实中的某个事物, 是该事物在编程中的抽象(无序的键值对的集合),多个数据的集合体(封装体),用于保存多个数据的容器
var person = {
name:'阿马',
age:33,
eat:funcition(){
console.log('吃货');
}
}
console.log( typeof obj.eat());
2. 为什么要用对象?
便于对多个数据进行统一管理,为了去描述某个复杂的事物
符合人类看待事物的一般规律
3. 创建对象?
3.1 使用关键词 new创建对象
var obj = new Object();
obj.name = '大哥';
obj.age = 34;
obj.gender = true;
obj.eat = function(){
console.log('吃卤煮~~');
}
console.log(obj.name); //大哥
console.log(obj);//34
obj.eat(); //吃卤煮~~
var obj2 = new Object();
obj2.name = '大嫂';
obj2.age = 60;
obj2.gender = false;
obj.eat = function(){
console.log('吃炒肝~~');
}
console.log(obj2.name);//大嫂
console.log(obj2);//60
obj2.eat();//吃炒肝~~
3.2 使用工厂类来创建对象
** 工厂类的弊端 只能创建单一类型的对象**
function createPerson(name,age,gender){
var obj = new Object();
obj.name = name;
obj.age = age;
obj.gender = gender;
obj.eat = function(){
console.log(obj.name+'吃卤煮~~');
}
return obj;
}
var person = createPerson('大哥',34,true);
var person = createPerson('大嫂',80,false);
3.3 使用构造方法创建对象
说明:
之前实例是有限制的。它们只创建单一类型的对象。有时我们需要创建相同“类型”的许多对象的方法。
创建一种“对象类型”的方法,是使用对象构造器函数。
使用new运算符调用构造函数,可以构造一个实例对象,用法如下
var objectName = new functionName (args)
参数说明如下
- objectName:返回的实例对象的名字
- FunctionName:构造函数,与普通函数基本相同
- args:实例对象初始化配置参数列表
- 用大写首字母对构造器函数命名是个好习惯。
-
在堆内存中开辟了一个空间,存储该对象
- this指向的是当前的实例对象
- this.属性的方式给当前对象添加属性或者方法
- 不需要return,直接将对象返回
- 构造函数会直接将对象给变量,而不是通过return返回的
3.3.1 创建构造器
function Person(name, age, sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
3.3.2 调用构造器
通过 new 关键词调用构造器函数可以创建相同类型的对象:
var 变量名字 = new 构造函数(值1,值2.。。)
var p1 = new Person("cuihua", 18, "男");
var p2 = new Person("gangtie", 19, "女");
var p3 = new Person("huahua",20,"x");
3.3.3 为对象添加属性
为已有的对象添加新属性:
p1.hobby = "eat"; //a添加
p2.name = '小宇'; //替换
有则改之,无则加免
新属性被添加到 p1,不是任何其他 person 对象,只是p1 的属性,与p2,p3无关
3.3.4 为对象添加方法
为已有的对象添加新方法:
p1.hobby = function () {
return "drink";
};
新方法被添加到 p1,不是任何其他 person 对象。只是p1 的方法,与p2,p3无关
3.3.5 内建JavaScript构造器
JavaScript 提供用于原始对象的构造器:
var x1 = new Object(); // 一个新的 Object 对象
var x2 = new String(); // 一个新的 String 对象
var x3 = new Number(); // 一个新的 Number 对象
var x4 = new Boolean(); // 一个新的 Boolean 对象
var x5 = new Array(); // 一个新的 Array 对象
var x6 = new RegExp(); // 一个新的 RegExp 对象
var x7 = new Function(); // 一个新的 Function 对象
var x8 = new Date(); // 一个新的 Date 对象
Math() 对象不再此列。Math 是全局对象。new 关键词不可用于 Math。
function Person(name,age,gender){
this.name = name;
this.age = age;
this.gender = gender;
this.eat = function(){
console.log(this.name+'吃卤煮~~');
}
}
var person = new Person('大哥',1000,true);
思考:如果在构造函数中return了一个基本数据类型和一个引用类型对象,那么构造方法返回的是什么
// 首先构造函数不允许写返回值
// 如果写了 返回的是基本数据类型则忽略
// 如果返回的是对象类型 则返回对象数据
function Cat(name,age){
this.name = name;
this.age = age;
return 1;
}
var c = new Cat('招财猫',1000);
console.log(c); //Cat {name: "招财猫", age: 1000}
function Cat(name,age){
this.name = name;
this.age = age;
return [1,2,3,4];
}
var c = new Cat('招财猫',1000);
console.log(c); // [1,2,3,4]
3.4 字面量创建对象
这是创建对象最简单的方法。
使用对象文字,您可以在一条语句中定义和创建对象。对象文字指的是花括号 {} 中的名称:值对(比如 age:18)。
var person = {name:"red romance", age:18, color:"yellow"};
也可以折行书写
var person = {
name:"red romance",
age:18,
color:"yellow"
};
4. JavaScript对象属性
- 属性指的是与 JavaScript 对象相关的值。
- JavaScript 对象是无序属性的集合。
- 属性通常可以被修改、添加和删除
4.1 定义JavaScript的属性
-
对象的属性是由键值对组成的
-
每个键值对,键和值之间用 :分隔
-
所有的键都被称作是这个对象的属性,值叫做属性值
-
对象的属性,本质上都是字符串,只不过大部分属性是可以省略引号不写的;少数情况会出现不符合命名规范的,就必须带引号
eg:‘man-type’:‘渣男马’ //这个属性名必须使用引号;属性名不符合命名规范就得带引号
var obj = {
name:'马志强',
'age':34,
gender:'female',
"height":175,
eat:function(){
console.log('吃货~');
},
'character-type':'渣男'//这个属性名必须使用引号;属性名不符合命名规范就得带引号
};
4.2 属性的增和改
通过简单的赋值,向已存在的对象添加新属性。
假设 person 对象已存在 - 那么您可以为其添加新属性:
-
属性的添加的点语法
点语法,写起来简单,但是某些场合无法使用.去操作
-
obj.weight = 90;
有则更改,无则添加 -
下面两种情况必须使用[],其余的都可以使用.语法
-
obj.character-type = '嘿嘿';
obj['chaeacter-type'] ='嘿嘿'
无法操作,因为.后面的属性名不合法,只能使用[]去操作
-
var a = 'aaa'; obj.a = 'bbb';
本意是要以变量当中的值为属性,添加一个‘bbb’的值 ‘aaa’:‘bbb’,这样写最终会把a当做对象的属性去操作,完全等价于obj[‘a’] = 'bbb’如果是要使用变量当中的值为属性,那么.语法也没办法操作;
var a = 'aaa'; person.a = '123'; console.log(person); //改为 person[a] = '123'; console.log(person);
-
-
-
中括号语法
obj['weight'] = 100;
有则更改,无则添加obj['character-type'] = '嘿嘿';
当对象的属性是不合法的名字必须使用[]var a = true; obj[a] = 'bbb';
如果我们需要以变量当中的值为属性去操作对象的话,必须使用[]
4.3 属性的删除
delete 关键词从对象中删除属性:
-
delete obj.age;
-
delete obj['character-type'];
-
delete obj[a];
-
delete 关键词 会同时删除属性的值和属性本身。
-
删除完成后,属性在被添加回来之前是无法使用的。
-
delete 操作符被设计用于对象属性。它对变量或函数没有影响。
4.4 属性的查询
var person = {name:“red romance”, age:18, color:“yellow”};
objectName.property
eg: person.ageobjectName["property"]
eg:person[“age”]objectName[expression]
eg: x = “age”; person[x]
4.5 for…in语句遍历对象属性
语法:
for (variable in object) {
要执行的代码
}
for…in 循环中的代码块会为每个属性执行一次。
案例:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>for in测试</title>
</head>
<body>
<script>
var person = {name:"Barry", age:18};
for(var x in person) {
console.log(x,person[x]);
}
</script>
</body>
</html>
var arr = [1,2,3];
arr.forEach(function(item,index){
console.log(index);
})
5. JavaScript对象方法
5.1 创建对象方法
methodName : function() {
// 业务逻辑代码
}
5.2 访问对象方法
objectName.methodName();
案例练习:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>优化</title>
</head>
<body>
<script>
var person = {
name : "Barry",
age : 18,
getname : function() {
return "诸葛钢铁";
}
};
console.log(person.getname());
</script>
</body>
</html>
思考:如果调用方法的时候没有添加圆括号,会发生什么? //返回方法体
5.3 this关键字
this是一个内置的变量,this经常在函数内部去使用,this在函数外部统统代表的是window,this本质上是一个对象,this这个变量当中存储的是一个对象的地址,this主要代表的是这个函数的执行者或者调用者是谁。
this的使用场合
-
普通函数内部 一般执行的时候都是window去执行的
function fn1() { console.log(this); // window } fn1();
思考:
function fn2() {
console.log(this); //window
function fn3() {
console.log(this); //window
}
fn3();
}
fn2();
-
方法内部 一般调用的时候执行者都是这个方法的对象
var obj = { eat:function(){ //称作方法 console.log(this); //obj console.log('吃'); } } obj.eat();//eat方法执行者是obj或者是函数的调用者
-
构造函数内部 this一般代表的是准备实例化出来的那个对象
说明:
函数当函数用又分为多种情况去使用:当普通函数用和当构造函数用 任何的函数都可以当普通函数用也可以当构造函数用 就看你调用函数的时候有没有加new 加了就是把函数当构造函数用,没加还是当普通函数用 函数是普通函数还是构造函数并不是定义说了算,而是调用说了算;
function Car(name,color,price){
this.name = name;
this.color = color;
this.price = price;
this.run = function(){
// console.log('5个油。。。');
console.log(this) //window
}
}
//此时就说这个函数是当普通函数用的
var result = Car('奔驰','black',200000);
console.log(result);
//此时这个函数内部的this 是window
//函数的返回值看的就是return,没有return就是undefined;
console.log(color);
//普通函数调用,本质是在window对象上增加了name color price run属性和值
//在外部,我们就可以通过这个window的属性拿到函数内部的局部变量的值;
var c1 = new Car('红旗','black',10000000);
console.log(c1);
c1.run();
//此时就说这个函数是当构造函数用的
//此时这个函数内部的this 是准备实例化出来的对象,因为构造函数本身就是实例化对象用的;
//返回值:如果没写return或者return后面是基本值,那么返回的就是实例化出来的对象本身,和return没关系
// 如果return后面是对象类型的数据,那么返回的就是对象数据,和实例化出来的对象没关系
-
事件回调函数内部:代表的就是添加事件监听的事件源
var li_list = document.getElementsByTagName('li'); for(var i = 0;i<li_list.length;i++){ // 循环的时候将每一个li都添加了一个点击事件 li_list[i].onclick = function(){ // innerHTML标签中的内容 this.innerHTML = '你绿了。。。。'; // this代表的是当前的点击对象 this.style.backgroundColor = 'green'; } }
-
call和apply调用的内部(后续讲解)
6. 面试题讲解
var a = {};
var obj1 = {
m: 2
}
var obj2 = {
n: 2
}
var obj3 = function() {};
a[obj1] = 4
a[obj2] = 5
a.name = 'kobe'
a[obj3] = 6;
console.log(a[obj1]) //6
console.log(a)
三、函数
1. 什么是函数?
具有特定功能的n条语句的封装体,只有函数是可执行的, 其它类型的数据是不可执行的,函数也是对象
2. 为什么要用函数?
- 提高代码复用
- 便于阅读和交流
- 把一个项目模块化
3. 如何定义一个函数
function 方法名/函数的名字(){
//要执行的代码
}
- 方法名字与变量名一样都必须是JavaScript合法的标识符。
- 在函数名之后是一个由小括号包含的参数列表,参数之间以逗号分隔。参数是可选的,没有数量限制。
- 在小括号之后是一个大括号,大括号内包含的语句就是函数体结构的主要内容。在函数体中,大括号是必不可少的,缺少大括号, JavaScript将会抛出语法错误
4. 函数的2种角色
- 函数: 通过()使用 ==> 就称之为函数
- 对象: 通过.使用 ==> 称之为: 函数对象
5. 如何调用(执行)函数
-
test() 普通函数调用
-
new test() 构造函数调用
-
obj.test() 普通函数调用
-
new obj.test() 构造函数调用(极少)
var obj = { name:'马大哥', age:34, test:function(name,age){ this.name = name; this.age = age; } }
new obj.eat();
```
- test.call/apply(obj)
6. 回调函数
6.1 什么函数才是回调函数?
定义的,你没有直接调用, 但最终它执行了(在特定条件或时刻)
6.2 常见的回调函数?
-
DOM事件函数
-
定时器函数
-
ajax回调函数(后面学)
-
生命周期回调函数(后面学)
7. IIFE[匿名函数自调用]
7.1 IIFE的定义
全称: Immediately-Invoked Function Expression 立即调用函数表达式
又叫做立即执行函数也叫做匿名函数自调用
function (){
console.log("i am IIFE");
}
发现报错啦!!!
-
解决方法只需要给匿名函数包裹一个括号即可:
(function (){ //由于没有执行该匿名函数,所以不会执行匿名函数体内的语句。 console.log("匿名函数不会报错了"); })
-
匿名函数后面加上一个括号即可立即执行!
(function (){ console.log("运行匿名函数"); })()
-
在函数前添加 !~ + - 一元运算符
!function (){ alert("heng"); }()
-
倘若需要传值,直接将参数写到括号内即可:
(function (str){ console.log("Hello "+str); })("World")
7.2 IIFE特点
1、匿名函数自调用是在定义的同时执行函数
2、匿名函数自调用只能执行一次
如果需要一个函数可以执行多次,这个函数必须是有名函数/具名函数
如果函数没有名字要想执行必须是自调用,但是只能执行一次
3、匿名函数自调用,函数整体不会发生预解析,但是函数内部执行代码是要去预解析
7.3 IIFE作用
- 防止外部命名空间污染
- 隐藏内部代码暴露接口
- 对项目的初始化,只执行一次
var a = 2
var b = 3
function sum(a,b) {
return a + b
}
var a = 'haha';
sum(a,b);
var a = 'haha';
(function () {
var a = 2
var b = 3
return a + b;
})()
8. 递归(了解)
练习:5的阶乘的递归
function fn(n){
if(n == 1){
return 1;
}
return n * fn(n-1);
}
console.log(fn(5));
下一篇:21.JS高级(二)
🌸友情推荐:全栈大佬笔记 Android领域肥宅