JavaScript03-对象、函数
1.对象的基本操作
// 1 基本数据类型。Number、String、Boolean、Null和Undefined。
// 2 对象。Object。
// 3 基本数据类型和对象的区别。
// 基本数据类型是一个独立的值,无法在程序中表示一些复杂的数据结构;
// 对象可以存储不同类型的数据,对象中的数据也被成为属性,向对象中添加数据就是添加属性。
// 1 创建一个新对象
let a = new Object();
console.log(a); // {}
// 2 向对象中添加属性
a.name = 'tom';
a.age = 20;
console.log(a); // {name: 'tom', age: 20}
// 3 读取对象中的属性。
console.log(a.name); // tom
// 当对象中没有访问的属性时,会返回undefined。
console.log(a.address); // undefined
// 当访问一个没有定义的变量时会报错。
// console.log(address); // 报错
// 4 删除对象中的属性
delete a.name;
console.log(a.name); // undefined
2.对象中的属性
// 1 对象的属性名可以是任意值,不需要遵守标识符的规范。
let a = new Object();
a.let = 'let';
console.log(a.let); // let
// 2 当属性名太特殊时就需要采用另外的命令方式。
//a.123$_= = 'tom'; // 报错
a['123$_='] = 'tom';
// 3 当属性名太特殊时就需要采用另外的命令方式来获取属性的值。
console.log(a['123$_=']); // tom
// 4 使用 a['']来操作属性时,可以将字符串声明为变量,这样操作更加的方便。
a.name = 'bob';
a.age = 15;
let b = 'name';
console.log(a[b]); // bob
// 5 属性的值可以是任意数据类型,Number、String、Boolean、Null、Undefined和对象。
3.JavaScript中的可变类型
- 变量是不可变类型,对象是可变类型。
// 1 当变量的值被修改时,只会影响变量自己,对其他的变量不会产生影响。
let a = 10;
let b = a;
a = 15;
console.log(a); // 15
console.log(b); // 10
// 2 当对对象进行修改时,如果有其他的变量也指向这个对象,则这个变量也会被影响。
let c = new Object();
c.name = 'tom';
let d = c;
c.name = 'bob';
console.info(d.name); // bob
// 3 e = null;也属于修改变量。变量属于不可变类型,对象属于可变类型。
let e = new Object();
e.name = 'bob';
let f = e;
e = null;
console.info(f); // {name: 'bob'}
- 变量和对象的内存图。
// 1 变量的内存图
let a = 10; // 声明一个变量a,a中保存的是地址0x0001,通过地址0x0001可以找到10,a --> 0x0001 ---> 10
let b = a; // 声明一个变量b,b中保存的是地址0x0002,通过地址0x0002可以找到10,b --> 0x0002 ---> 10
a = 15; // 给a赋值5,也就是修改地址0x0001的值为15,但是没有修改0x0002地址的值,所以b还是10。
// 2 对象的内存图。
// 声明一个变量c,c的地址是0x001,地址0x001中保存一个对象,
// 其中对象的name属性也指向一个地址,这个地址保存的值字符串bob。
let c = new Object();
c 0x001 ---> {name->0xa01} ---> 0xa01保存的是值bob
// 声明一个变量d,d的地址也是0x001,。
let d = c;
4.对象的相等和全等比较
// 1 对象的相当和全等比较。两个对象进行比较时,相等和全等比较的都是对象的地址。
let a1 = new Object();
let a2 = new Object();
let a3 = a1;
console.info(a1 == a2); // false
console.info(a1 === a2); // false
console.info(a1 == a3); // true
console.info(a1 === a3); // true
// 2 在声明对象时可以使用const。保证const o,o是不可变的。
const o = new Object();
console.info(o);
5.对象中属性的判断
// 1 判断对象中是否有某个属性。
let l = new Object();
l.name = 'tom';
l.age = 20;
console.info('name' in l); // true
console.info('n' in l); // false
// 2 for...in...遍历对象中的数据
for(let n in l) {
// n,就是对象中属性对应的字符串。
console.info(n); // name age
// 判断n是对象的数据。
console.info(n in l); // true false
// 获取属性n对应的字符串。
console.log(l[n]); // tom 20
}
6.字面量创建对象
let a = new Object();
a.name = 'tom';
// 1 会在内存中创建一个字符串'bob',然后将字符串'bob'的内存地址赋值给a.name。
a.name = 'bob';
// 2 创建对象的三种方式。
let b = new Object();
let c = Object();
// 字面量创建对象
let d = {};
// 字面量创建对象并赋值。
let e = {
name: 'tom',
age: 18,
};
console.log(e); // {name: 'tom', age: 18}
console.log(typeof e); // object
7.对象的垃圾回收
// 1 如果一个对象没有被任何变量引用,那么这个对象就是垃圾对象。
// 2 垃圾对象会占用大量的内存空间,从而导致程序运行速度变慢。
// 3 JS拥有自动垃圾回收机制,会自动回收垃圾对象。
let a1 = {};
let a2 = {};
// 将不在使用的对象设置为null,JS会就自动回收。
a2 = null;
8.函数
- 函数的基本操作。
// 1 函数
// 函数也是一个对象并且函数和对象的功能一样。
// 不同的是:对象用来存储属性;函数用来存储代码,函数中的代码可以被反复的调用。
// 2 创建一个函数。
function f() {
console.log('f1');
}
// 3 调用函数
f(); // f1
// 4 输出一个函数
/*
ƒ f() {
console.log('f1');
}
*/
console.log(f);
console.log(typeof f); // function
- 函数的声明和调用。
// 1 函数声明
function f1() {
console.log('f1');
}
// 2 函数表达式声明一个函数,函数表达式可以将一个函数赋值给一个变量。
let f2 = function () {
console.log('f2');
};
// 函数表达式的调用
f2();
console.log(typeof f2); // function
- 函数的参数。
// 1 形参,在定义函数时,可以在函数的()中指定任意数量的形参。
// 在函数()中定义形参,就相当于定义了变量,但是没有赋值。
// 2 实参,调用函数时传递的参数,实参会传递给形参。
// 3 函数调用传递参数时,JS不会检查参数的个数是否匹配。
// 4 如果实参少于形参,则没有实参的形参默认是undefined。
// 5 如果实参多于形参,则多余的实参不会使用。
function f3(a, b) {
console.log(`a = ${a}, b = ${b}`)
}
f3('hello'); // a = hello, b = undefined
f3('1', '2', '3'); // a = 1, b = 2
- 函数的返回值。
// 1 函数的返回值可以是任意类型,基本数据类型、对象和函数
function f4(a, b) {
return a + b;
}
let a = f4(1, 2);
console.log(a); // 3
// 2 如果不写return,或者return;则相当与return undefined;
function f5(a, b) {
return;
}
a = f5();
console.log(a); // undefined
// 3 函数的返回值可以是一个对象。
// {'a':a, 'b': b} 等价于 {a: a, b: b} 等价于 {a, b}
function f6() {
let a = 10;
let b = 20;
// 将a和b返回,等价于return {'a':a, 'b': b};
//return {'a':a, 'b': b};
//return {a: a, b: b};
// 如果要将a和b返回,也可以写为 return {a, b};
return {a, b};
}
console.info(f6()); // {a: 10, b: 20}
- 函数的其他规则和立即执行函数。
// 1 JS中禁止以function开头的函数没有名字。
// 报错 Uncaught SyntaxError: Function statements require a function name
// function () {
//
// }
// 2 立即执行函数。
// 立即执行函数会在函数创建后立即调用,并且只会执行一次。
(function () {
console.info('立即执行函数的第一种写法')
})();
(function () {
console.info('立即执行函数的第二种写法')
}());
9.方法
// 1 如果一个对象的属性是一个函数,则我们称这个函数是这个对象的方法。
let a = {
name: 'tom',
test:function () {
console.log('方法');
}
};
// 调用对象中的方法。
a.test(); // 方法
// 2 函数中声明方法的简写。
let b = {
name: 'bob',
test() {
console.log('test');
}
};
b.test(); // test
10.全局作用域
// 作用域,变量的作用范围。
// 作用域的分类。全局作用域;局部作用域:块作用域和函数作用域。
// 1 全局作用域
// 直接写在script标签中的内容,都属于全局作用域。
// 全局作用域在页面加载时创建,在页面关闭是销毁。
// 全局作用域中定义的变量时全局变量,全局作用域中定义的函数时全局函数。
// 全局变量可以在任意位置访问,全局函数也可以在任意位置访问。
// 定义一个全局作用域的变量
let a = 10;
// 定义一个全局作用域的函数
function f1() {
console.log('f1');
}
// 2 window,全局作用域中存在一个全局对象window,window代表浏览器窗口。
// 在全局作用域中var声明的变量都会作为window的属性保存。
// 使用function声明的方法都会作为window的方法保存。
// let声明的变量不会存储在window中。
var b = 'tom';
console.log(window.b); // tom
function f2() {
console.log('f2');
}
window.f2(); // f2
let c = 'bob';
console.log(window.c); // undefined
// 直接给一个没有声明过的变量赋值,实际上就是给window对象中添加属性。
d = 'd';
console.log(window.d); // d
console.log(d); // d
11.变量和函数的提升
- 变量的提升。
// console.log(a); // 报错 Uncaught ReferenceError: a is not defined
console.log(window.a); // undefined
a = 10;
// console.log(b); // 报错 Uncaught ReferenceError: Cannot access 'b' before initialization
let b = 20;
// 变量的提升,使用var声明的变量会在所有代码执行前被创建,但是不会进行赋值。
// 所有我们可以在变量声明前就对其访问,这个特点我们称为变量的提升。
console.log(c); // undefined
var c = 30;
- 函数的提升。
// 使用function声明的函数,会在所有代码执行前被创建。
// 所以我们可以在函数被创建前对其进行调用,这个特点我们称为函数的提升。
f1(); // f1
function f1() {
console.log('f1');
}
// 相当与变量的提升。
// d(); // Uncaught TypeError: d is not a function
console.log(d); // undefined
var d = function () {
console.log('d');
}
- 变量和函数提升练习。
console.log(a); // 4,变量和函数提升会进行覆盖,所有这里的a是包含console.log('4');的函数。
var a = 1;
console.log(a); // 1
function a() {
console.log('2');
}
console.log(a); // 1,console.log('2');函数已经在函数提升式执行了,所有这里的a依然是1
a = 3;
console.log(a); // 3
function a() {
console.log('4');
}
console.log(a); // 3
a = function () {
console.log('5');
};
console.log(a); // 5
12.函数的作用域
// 1 函数作用域。
// 函数作用域在函数调用时创建,调用结束时销毁。
// 函数在每次调用时都会产生一个新的作用域,同时每个函数作用域相互独立。
// 在函数中声明的变量是局部变量,局部变量只能在函数内部访问,不能在函数外面访问。
// 在函数中声明变量时不使用var和let,则变量会变成全局变量。
function f1() {
a = 1;
}
f1();
// 函数用声明变量没有使用var和let,a变为全局变量,但是需要调用一次a所在的函数f1(),a才能访问。
// 如果没有调用a所在的函数f1(),则访问a会报错,Uncaught ReferenceError: a is not defined
console.log(a); // a
// 变量和函数的提升,在函数作用同样适用。
function f2() {
// 变量b发生了提升。
console.log(b); // undefined
var b = 10;
}
f2();
13.作用域链
// 1 作用域链,当我们访问一个变量时,JS会先在当前作用域中寻找。
// 如果有则直接使用;如果没有,则在当前作用域的上一级寻找,依次类推,只要找到全局作用域,
// 如果全局作用域还是没有,则报错,Uncaught ReferenceError: x is not defined
let a = 10;
function f1() {
let a = 20;
console.log(a);
}
f1(); // 20
// 2 JS中的作用域链也叫做词法作用域。
// 词法作用域:函数作用域由定义它的位置所决定,和调用位置无关。
let b = 10;
function f2() {
console.log(b);
}
function f3() {
let b = 20;
f2();
}
f3(); // 10
// 3 b的作用域由c的上一级决定。
let c = 10;
function f4() {
let c = 20;
return function () {
console.log(c);
}
}
let d = f4(); // 20
d();
// 4 函数中var定义的变量。
let n1 = 10;
function f5() {
// 在函数中使用var定义变量,变量会被提升,所以这里的n1 = 20,n1也是局部变量。
n1 = 20;
var n1 = 30;
console.log(n1); // 30
}
f5();
console.log(n1); // 10
// 5 函数中let定义的变量。
let n2 = 10;
function f6() {
// 如果在函数中使用let定义变量,变量不会被提升,
// 所以会报错 Uncaught ReferenceError: Cannot access 'n2' before initialization
n2 = 20;
let n2 = 30;
console.log(n2); // 30
}
f6();
console.log(n2); // 10
14.this
// this表示当前调用的对象。
// 1 在调用函数时,浏览器每次都会向函数中传递一个隐含的参数this。
// 2 this表示当前调用的对象。
// 3 当我们调用一个函数时,this是window对象;当我们调用对象中的方法时,this就是当前对象。
let a = 10;
function f1() {
console.log(this.a);
}
let o1 = {
a: 20,
f: f1
};
let o2 = {
a: 30,
f: f1
};
o1.f(); // 20
o2.f(); // 30
f1(); // undefined,window中没有a属性。
// 输出变量
let name = 'tom';
let b = {
name:'bob',
out: function () {
// 直接输出name,相当与输出变量name,所以会向上找name,而name:'bob'是属性,所以输出的是tom。
// name -> tom
// 输出属性name,所以输出的是bob。
// b.name -> bob
// this.name -> bob
console.log(name);
}
};
b.out(); // tom