arguments参数

  • 事实上在函数有一个特别的对象:arguments对象
    • 默认情况下,arguments对象是所有(非箭头)函数中都可用的局部变量;
    • 该对象中存放着所有的调用者传入的参数,从0位置开始,依次存放;
    • arguments变量的类型是一个object类型( array-like ),不是一个数组,但是和数组的用法看起来很相似;
    • 如果调用者传入的参数多余函数接收的参数,可以通过arguments去获取所有的参数;

回调函数

  • 既然函数可以作为一个值相互赋值,那么也可以传递给另外一个函数。image.png
  • foo这种函数我们也可以称之为高阶函数;
  • 高阶函数必须至少满足两个条件之一:
    • 接受一个或多个函数作为输入;
    • 输出一个函数;
  • 匿名函数的理解:
    • 如果在传入一个函数时,我们没有指定这个函数的名词或者通过函数表达式指定函数对应的变量,那么这个函数称之为匿名 函数。

1.函数回调的概念理解

1
2
3
4
5
6
7
8
9
// 1.函数回调的概念理解
function foo(fn) {
// 通过fn去调用bar函数的过程, 称之为函数的回调
fn()
}
function bar() {
console.log("bar函数被执行了~")
}
foo(bar)

2.函数回调的案例

1
2
3
4
5
6
7
8
9
10
11
12
13
// 2.函数回调的案例
function request(url, callback) {
console.log("根据URL向服务器发送网络请求")
console.log("需要花费比较长的时间拿到对应的结果")
var list = ["javascript", "javascript学习", "JavaScript高级编程"]
callback(list)
}


function handleResult(res) {
console.log("在handleResult中拿到结果:", res)
}
request("url", handleResult)

3.函数回调的案例重构

1
2
3
4
5
6
7
8
9
10
11
12
// 3.函数回调的案例重构
function request(url, callback) {
console.log("根据URL向服务器发送网络请求")
console.log("需要花费比较长的时间拿到对应的结果")
var list = ["javascript", "javascript学习", "JavaScript高级编程"]
callback(list)
}

// 传入的函数是没有名字, 匿名函数
request("url", function(res) {
console.log("在handleResult中拿到结果:", res)
})

image.png

对象的常见操作

  • 访问对象的属性;image.png
  • 修改对象的属性;image.png
  • 添加对象的属性;image.png
  • 删除对象的属性:delete操作符 image.png

方括号和引用的使用

  • 为什么需要使用方括号呢?
    • 对于多次属性来说,JavaScript是无法理解的。image.png
  • 这是因为点符号要求 key 是有效的变量标识符
    • 不包含空格,不以数字开头,也不包含特殊字符(允许使用 $ 和 _);
  • 这个时候我们可以使用方括号:
    • 方括号运行我们在定义或者操作属性时更加的灵活;
    • image.png

对象的遍历

  • 对象的遍历(迭代):表示获取对象中所有的属性和方法。
    • Object.keys() 方法会返回一个由一个给定对象的自身可枚举属性组成的数组;
  • **遍历方式一:普通for循环 **
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var info = {
name: "why",
age: 18,
height: 1.88
}

// console.log(Object.keys(info))

// 对对象进行遍历
// 1.普通for循环
var infoKeys = Object.keys(info)
for (var i = 0; i < infoKeys.length; i++) {
var key = infoKeys[i]
var value = info[key]
console.log(`key: ${key}, value: ${value}`)
}

image.png

  • **遍历方式二:for in 遍历方法 **
1
2
3
4
for (var key in info) {
var value = info[key]
console.log(`key: ${key}, value: ${value}`)
}

栈内存和堆内存

  • 我们知道程序是需要加载到内存中来执行的,我们可以将内存划分为两个区域:栈内存和堆内存。
    • 原始类型占据的空间是在栈内存中分配的;
    • 对象类型占据的空间是在堆内存中分配的;

值类型和引用类型

  • 原始类型的保存方式:在变量中保存的是值本身
    • 所以原始类型也被称之为值类型;
  • 对象类型的保存方式:在变量中保存的是对象的“引用”
    • 所以对象类型也被称之为引用类型;

思考下面的现象

现象一:两个对象的比较
image.png
现象二:引用的赋值

1
2
3
4
5
6
7
8
9
10
11
// // 2.现象二: 引用的赋值
var info = {
name: "why",
friend: {
name: "kobe"
}
}

var friend = info.friend
friend.name = "james"
console.log(info.friend.name) // james

函数传递-引用传递-创建新对象.png
3.现象三: 值传递

1
2
3
4
5
6
function foo(a) {
a = 200
}
var num = 100
foo(num)
console.log(num) // 100

4.现象四: 引用传递,
但是在函数中创建了一个新对象, 没有对传入对象进行修改

1
2
3
4
5
6
7
8
9
10
function foo(a) {
a = {
name: "why"
}
}
var obj = {
name: "obj"
}
foo(obj)
console.log(obj)//name:"obj"

函数传递-引用传递-创建新对象.png
5.现象五: 引用传递
** 但是对传入的对象进行修改**

1
2
3
4
5
6
7
8
9
function foo(a) {
a.name = "why"
}

var obj = {
name: "obj"
}
foo(obj)
console.log(obj)//name="why"

函数传递-引用传递-修改引用属性.png

this指向什么?

  • 目前掌握两个this的判断方法:
    • 在全局环境下面,this指向window;
    • 通过对象调用,this指向调用的对象;

情况一: 如果普通的函数被默认调用, 那么this指向的就是window

1
// 情况一: 如果普通的函数被默认调用, 那么this指向的就是window   
1
2
3
4
5
6
7
8
9
10
11
function foo(name, age) {
console.log(arguments)
console.log(this)
}
foo("abc", 123)


function sayHello(name) {
console.log(this)
}
sayHello()

image.png
情况二: 如果函数它是被某一个对象来引用并且调用它, 那么this会指向这个对象(调用的那个调用)

1
2
3
4
5
6
7
8
9
 var obj = {
name: "why",
running: function() {
console.log(this)
console.log(obj)
console.log(this === obj)
}
}
obj.running()

image.png
题目一:
谁调用就指向谁

1
2
3
4
5
6
7
8
var obj = {
name: "why",
running: function () {
console.log(this)
}
}
var fn = obj.running
fn() // window

image.png
题目二:
谁调用就指向谁

1
2
3
4
5
6
7
8
function bar () {
console.log(this) // obj对象
}
var obj = {
name: "why",
bar: bar
}
obj.bar()// obj对象

image.png

JavaScript中的类(ES5)

  • JavaScript中的构造函数是怎么样的?
    • 构造函数也是一个普通的函数,从表现形式来说,和千千万万个普通的函数没有任何区别;
    • 那么如果这么一个普通的函数被使用new操作符来调用了,那么这个函数就称之为是一个构造函数;
  • 如果一个函数被使用new操作符调用了,那么它会执行如下操作:
      1. 在内存中创建一个新的对象(空对象);
      1. 这个对象内部的[[prototype]]属性会被赋值为该构造函数的prototype属性;
      1. 构造函数内部的this,会指向创建出来的新对象;
      1. 执行函数的内部代码(函数体代码);
      1. 如果构造函数没有返回非空对象,则返回创建出来的新对象;
  • 工厂方法创建对象有一个比较大的问题:我们在打印对象时,对象的类型都是Object类型
  • 我们来通过构造函数实现一下: image.png
    • 这个构造函数可以确保我们的对象是有Person的类型的(实际是constructor的属性)