基于尚硅谷的尚硅谷JavaScript高级教程提供笔记撰写,加入一些个人理解

github源码

博客下载

数据类型的分类和判断

主要问题

分类

基本(值)类型
  • Number ----- 任意数值 -------- typeof
  • String ----- 任意字符串 ------ typeof
  • Boolean ---- true/false ----- typeof
  • undefined --- undefined ----- typeof/===
  • null -------- null ---------- ===
对象(引用)类型
  • Object --任意对象--- typeof/instanceof
  • Array ---特别的对象类型(下标/内部数据有序)--- instanceof
  • Function --特别的对象类型(可执行)-- typeo

数据类型判断

  • typeof:

    typeof返回值是数据类型的字符串表达

    例如:

    var a = 3
    console.log(typeof a==='number');//输出true

    可以区别: 数值, 字符串, 布尔值, undefined, function

    不能区别: null与对象, 一般对象与数组

    typeof判断null为object

  • instanceof

    专门用来判断对象数据的类型: Object, Array与Function

  • ===

    可以判断: undefined和null

    简单来说,===只能判断出只有一个值的数据类型

相关问题

undefined与null的区别?

undefined代表定义了但没有赋值

null代表赋值了, 只是值为null

 // 1. undefined与null的区别?
var a
console.log(a);//undefinde
a = null
console.log(a);//null

什么时候给变量赋值为null呢?

变量将指向一个对象, 但对象此时还没有确定

让变量指向的对象成为垃圾对象

 // 2. 什么时候给变量赋值为null呢?
//初始
var b = null//初始赋值为null,表明将要赋值为对象
//中间
b = ['atguigu', 12]//确定对象就赋值
//结束
b = null// 让b指向的对象成为垃圾对象(被垃圾回收器回收)

严格区别变量类型与数据类型?(平常不会严格区分)

js的变量本身是没有类型的, 变量的类型实际上是变量内存中数据的类型

变量类型:(变量内存值的类型)

基本类型: 保存基本类型数据的变量

引用类型: 保存对象地址值的变量

数据类型:

基本类型

对象类型

数据,变量, 内存的理解

主要问题

什么是数据?

  • 在内存中可读的, 可传递,可运算的保存了特定信息的'东东',本质就是0101二进制

  • 一切皆数据, 函数也是数据

  • 在内存中的所有操作的目标: 数据

    • 算术运算

    • 逻辑运算

    • 赋值

    • 调用函数传参

什么是变量?

  • 值可以变化的量, 由变量名与变量值组成
  • 一个变量对应一块小内存, 变量名用来查找到内存, 变量值就是内存中保存的内容

什么是内存?

  • 内存条通电后产生的存储空间(临时的)

    产生和死亡: 内存条(集成电路板)>通电>产生一定容量的存储空间>存储各种数据>断电==>内存全部消失

    内存的空间是临时的, 而硬盘的空间是持久的

  • 一块内存包含2个方面的数据

    • 内部存储的数据(一般数据/地址数据)
    • 内存地址值
  • 内存空间的分类

    • 栈空间: 全局变量和局部变量
    • 堆空间: 对象

内存,数据, 变量三者之间的关系

  • 内存是容器, 用来存储不同数据
  • 变量是内存的标识, 通过变量我们可以操作(读/写)内存中的数据

相关问题

赋值与内存的问题

问题: var a = xxx, a内存中到底保存的是什么?

 var a = 3 // 保存3
a = function () {
}//保存地址值
var b = 'abc'
a = b // b保存的数据'abc'
b = []
a = b // b保存的地址值

xxx是一个基本数据,保存的就是这个数据

xxx是一个对象,保存的是对象的地址值

xxx是一个变量,保存的是xxx的内存内容(可能是基本数据,也可能是地址值)

关于引用变量赋值问题

  • n个引用变量指向同一个对象, 通过一个引用变量修改对象内部数据, 其他所有引用变量也看得见
    var obj1 = { name: 'Tom' }
var obj2 = obj1
obj2.age = 12
console.log(obj1.age);//12 function fn(obj) {
obj.name = 'Bob'
}
fn(obj1)
console.log(obj2.name);//Bob
  • 2个引用变量指向同一个对象,让一个引用变量指向另一个对象, 另一个引用变量还是指向原来的对象
 var a = { age: 12 }
var b = a
a = { name: 'Jack', age: 13 }
console.log(b.age, a.name, a.age);//12 Jack 13
/*
这里记住一点,是将实参a赋值给形参obj,即 obj=a,此时他们指向同一对象。执行obj={age:15},obj指向发生改变,而a指向未发生改变
*/
function fn2(obj) {
obj = { age: 15 }
}
fn2(a)
console.log(a.age);//13

在js调用函数时传递变量参数时, 是值传递还是引用传递

对这个问题可以有着两种理解,第一种是理解为两个都是值传递,只是这个值可以是基本数据,也可以是地址数据。第二种则是把传递的地址值看作是引用传递,不过一般来说都当做是值传递。

    var a = 3
function fn(a) {
a = a + 1
}
fn(a)// 传的不是a,而是3这个值
console.log(a);// 3
/*
执行到:fn(a);先读到a是3,把a的值传给形参a,形参a去加1,输出为4。
实参a还是实参a,所以最后输出a仍然是3。这里是基本值传递。
*/
function fn2(obj) {
console.log(obj.name);
}
var obj = { name: 'Tom' }
fn2(obj)
/*
执行到:fn2(obj);把obj中的内容(不是把{name:‘tom’}传递给形参obj,
是把obj的地址值传给形参obj,只是地址值指向的是 {name:‘tom’})传递给形参obj。
这里是地址值传递。
*/

JS引擎如何管理内存

  1. 内存生命周期
  • 分配需要的内存空间,得到使用权
  • 存储数据,可以反复操作
  • 释放当前的内存空间
  1. 释放内存

为执行函数分配的栈空间内存(局部变量): 函数执行完自动释放

存储对象的堆空间内存(对象): 当内存没有引用指向时, 对象成为垃圾对象, 垃圾回收器后面就会回收释放此内存

    var a = 3
var obj = {}// 执行到这里,一共开辟了3个内存空间
obj = null // obj指向的对象内存空间被释放,obj不释放,手动释放 function fn() {
var b = {} // 只有函数被执行的时候才会开辟内存空间,即 fn()调用
}
fn()
/*
fn()执行完,b被自动释放,b所指向的对象在后面的某个时刻由垃圾回收器回收
*/

对象的理解和使用

主要问题

什么是对象

  • 代表现实中的某个事物, 是该事物在编程中的抽象
  • 多个数据的集合体(封装体)
  • 用于保存多个数据的容器

为什么要用对象?

便于对多个数据进行统一管理

对象的组成

属性
  • 代表现实事物的状态数据
  • 由属性名和属性值组成
  • 属性名都是字符串类型, 属性值是任意类型
属性的分类
  • 一般属性 : 属性值不是function 描述对象的状态
  • 方法 : 属性值为function的属性 描述对象的行为

特别的对象

  • 数组: 属性名是0,1,2,3之类的索引
  • 函数: 可以执行的

如何操作内部属性(方法)

  • obj.属性名
  • obj['属性名'] 一般不用,但通用

相关问题

什么时候必须使用['属性名']的方式?

  • 属性名不是合法的标识名(包含特殊字符:- 空格等)
  • 属性名不确定
 // 创建对象
var p = {}
/*情形一: 属性名不是合法的标识名*/
/*需求: 添加一个属性: content-type: text/json */
p.content-type = 'text/json' //不正确
p['content-type'] = 'text/json'
/*情形二: 属性名不确定*/
var prop = 'xxx' // 我们想让这个值(xxx)做属性名
var value = 123
p.prop = value //不正确 这么写的属性名是prop
p[prop] = value
console.log(p['content-type'], p[prop])

函数的理解和使用

主要问题

什么是函数?

  • 具有实现特定功能的n条语句的封装体
  • 只有函数是可执行的, 其它类型的数据是不可执行的
  • 函数也是对象

为什么要用函数?

  • 提高复用性
  • 便于阅读交流

如何定义函数?

  • 函数声明
  • 表达式
    fn1()// 输出fn1
fn2()// 输出undefined
//函数声明
function fn1() {
console.log('fn1');
}
//表达式
var fn2 = function () {
console.log('fn2');
}

区别:js中的变量提升

  • 函数声明可以在声明前调用
  • 表达式不能在声明前调用,输出为undefined

如何调用(执行)函数?

  • test():直接调用
  • new test():new调用
  • obj.test():对象调用
  • test.call/apply(obj):临时让test成为obj的方法进行调用
    var obj = {}
function test2() {
this.xxx = 'atguigu'
}
test2.call(obj) // 可以让一个函数成为指定任意对象的方法进行调用
//test2.apply(obj)
console.log(obj.xxx) // atguigu

这里我的想法是,call和apply改变了函数test2中的this指向,将函数test2中的this指向从window改变,指向call和apply传入的对象(后面有讲到this的指向问题)

函数也是对象

  • instanceof Object===true
  • 函数有属性: prototype
  • 函数有方法: call()/apply()
  • 可以添加新的属性/方法

函数的3种不同角色

  • 一般函数 : 直接调用
  • 构造函数 : 通过new调用
  • 对象 : 通过.调用内部的属性/方法

回调函数的理解

  • 什么函数才是回调函数?

    • 你定义的
    • 你没有调用
    • 但它最终执行了(在一定条件下或某个时刻)
  • 常用的回调函数
    • dom事件回调函数
    • 定时器回调函数
    • ajax请求回调函数(后面讲解)
    • 生命周期回调函数(后面讲解)

匿名函数自调用:

 (function (i) {
var a = 4
function fn() {
console.log('fn ', i+a)// 7
}
fn()
})(3)
  • 专业术语为: IIFE (Immediately Invoked Function Expression) 立即调用函数表达式

作用

  • 隐藏内部实现
  • 不污染外部命名空间
  • 编码js模块

this是什么?

  • 任何函数本质上都是通过某个对象来调用的,没有直接指定就是window
  • 所有函数内部都有一个变量this
  • 它的值是调用函数的当前对象

如何确定this的值?

  • test():window
  • obj.test():obj
  • new test():新建的对象
  • test.call(obj):obj

前置知识:

本质上任何函数在执行时都是通过某个对象调用的

function Person(color) {
console.log(this)
this.color = color;
this.getColor = function () {
console.log(this)
return this.color;
};
this.setColor = function (color) {
console.log(this)
this.color = color;
};
} Person("red"); //this是谁? window var p = new Person("yello"); //this是谁? p p.getColor(); //this是谁? p var obj = {};
p.setColor.call(obj, "black"); //this是谁? obj var test = p.setColor;
test(); //this是谁? window function fun1() {
function fun2() {
console.log(this);
} fun2(); //this是谁? window
}
fun1();

补充

分号问题

  1. js一条语句的后面可以不加分号

  2. 是否加分号是编码风格问题, 没有应该不应该,只有你自己喜欢不喜欢

  3. 在下面2种情况下不加分号会有问题

    小括号开头的前一条语句

    中方括号开头的前一条语句

    解决办法: 在行首加分号

 // 情形一: 小括号开头的前一条语句
var a = 3
;(function () {
})()
/*
错误理解: 将3看成是函数调用
var a = 3(function () {
})
*/
// 情形二: 中方括号开头的前一条语句
var b = 4
;[1, 3, 5].forEach(function (item) {
console.log(item)
})
/*
错误理解:
b= 4[5].forEach(function(e){
console.log(e)
})*/

最新文章

  1. Servlet3.0的可插拔功能
  2. 黄永成-thinkphp讲解-个人博客讲解25集
  3. C#入门经典第五版之变量的更多内容编码题训练
  4. hexo 搭建博客
  5. jQuery实现图片延迟加载
  6. android-exploitme(三):安全连接
  7. C#_IComparable实例 - 对象ID进行排序
  8. Being a Hero
  9. mysql grant 示例
  10. AFNetworking自带的解析图片的方法
  11. java中的异常机制(编译时异常)
  12. Java的selenium代码随笔(1)
  13. SQL*Plus命令
  14. eclipse回退到上个版本
  15. RecyclerView错误
  16. 如何:声明、实例化和使用委托(C# 编程指南)
  17. 【图像处理】openCV光流法追踪运动物体
  18. gdb调试器学习链接
  19. Unity中的网格与材质球合并
  20. compareTo 返回为整数 调用者比参数大;返回负数 调用者比参数小

热门文章

  1. java基础———标识符和关键字
  2. spring boot 分布式session实现
  3. 【java】学习路线4-对象、嵌套引用、匿名对象
  4. Can't pickle local object '_createenviron.<locals>.encodekey'报错解决
  5. 离线方式安装高可用RKE2 (版本: v1.22.13+rke2r1)记录
  6. immutable 与 stable 函数的差异
  7. File类、FileOutputStream
  8. HashMap不安全后果及ConcurrentHashMap线程安全原理
  9. 前端 vue表格数据导出Excel 文件实现
  10. Elasticsearch:使用 Nginx 来保护 Elastic Stack