一、认识对象
对象(object)是 “键值对” 的集合,表示属性和值的映射关系。
()代表优先级,{}对象[]数组
var xiaoming = {
name: '小明',
age: 12,
sex: '男',
hobbies: ['足球', '编程']
};
- 属性名(键名,key): 属性值(value)
- JS 中,大括号表示对象
- 最后的属性后面不加逗号
- {} 后加上分号
1.1 对象的语法
k 和 v 之间用冒号分隔,每组 k:v 之间用逗号分隔,最后一个 k:v 对后可以不书写逗号。
var obj = {
k: v,
K: v,
K: v,
K: v
};
1.2 属性是否加引号
如果对象的属性键名不符合 JS 标识符命名规范,则这个键名必须用引号包裹。
注意:对象中的 key 本身就是字符串格式,只是符合 JS 标识符命名规范的可以省略引号!
var xiaoming = {
name: '小明',
age: 12,
sex: '男',
hobbys: ['足球', '游泳', '编程'],
'favorite-book': '舒克和贝塔'
// 属性名中有短横,不符合JS标识符命名规范,属性名必须用引号包裹。
};
1.3 属性的访问
可以用“点语法”访问对象中指定键的值。
xiaoming.name; // '小明'
xiaoming.age; // 12
xiaoming.hobbys; // ['足球', '游泳', '编程']
如果属性名不符合 JS 标识符命名规范,则必须用方括号的写法来访问。
方括号
[]中只能是字符串类型!任何对象的属性名都可以通过
[]来访问,只要把属性名写为字符串的形式。
xiaoming['favorite-book']; // '舒克和贝塔'
如果属性名以变量形式存储,则必须使用方括号形式。
var obj = {
a: 1,
b: 2,
c: 3
};
var key = 'b';
console.log(obj.key); // undefined
console.log(obj[key]); // 2
1.4 属性的更改
直接使用赋值运算符重新对某属性赋值即可更改属性。
var obj = {
a: 10
};
obj.a = 30;
obj.a++;
1.5 属性的创建
如果对象本身没有某个属性值,则用点语法赋值时,这个属性会被创建出来。
var obj = {
a: 10
};
obj.b = 40;
var obj = {
a: 10
};
obj['zjr-b'] = 40;
1.6 属性的删除
如果要删除某个对象的属性,需要使用 delete 操作符。
var obj = {
a: 1,
'zjr-b': 2
};
delete obj.a;
delete obj['zjr-b'];
二、对象的方法
2.1 认识方法
如果某个属性值是函数,则它也被称为对象的 “方法”。
var xiaoming = {
name: '小明',
age: 12,
sex: '男',
hobbys: ['足球', '游泳', '编程'],
'favorite-book': '舒克和贝塔',
// sayHello方法
sayHello: function () {
console.log('你好我是小明,今年12岁,我是个男生');
}
};
2.2 方法的调用
使用 “点语法” 可以调用对象的方法。
xiaoming.sayHello();
2.3 方法和函数
方法也是函数,只不过方法是对象的 “函数属性”,它需要用对象打点调用。
在正式学习了什么是 “方法” 之后,就能深入理解之前我们学习的一些函数的书写形式了,比如:
console.log();
Math.ceil();
2.4 对象的遍历
和遍历数组类似,对象也可以被遍历,遍历对象需要使用 for...in... 循环。
使用 for...in... 循环可以遍历对象的每个键。
在后续的 ES6 相关课程中,还会学习新的对象遍历的方式。
【for...in...循环】
// k: 循环变量,它会依次成为对象的每一个键
// obj: 要遍历的对象
for (var k in obj) {
console.log('属性' + k + '的值是' + obj[k]);
}
【案例】
var obj = {
a: 11,
b: 22,
c: 88
};
for (var k in obj) {
console.log('对象obj的属性' + k + '的值是' + obj[k]);
}
/*
对象obj的属性a的值是11
对象obj的属性b的值是22
对象obj的属性c的值是88
*/
var zjr = {
name: 'jerry',
love: [180, 18, 1800000],
home: {
mm: 'glp',
bb: 'zyj'
}
};
for (var i in zjr) {
//i得到的是的是字符串形式的属性名
console.log(i);
console.log(typeof i);
//获取属性名对应的值
console.log(zji[i])
}
/*
name
string
string
love
string
object
home
string
object
*/
let students=[ { name:'小明',age:18,gender:'男',hometown:'河北省' }, { name:'小红',age:19,gender:'女',hometown:'广东省' }, { name:'小蓝',age:20,gender:'男',hometown:'河南省' }]
for(let i=0;i<students.length;i++){
cosole.log(i) //1 2 3 下标索引号
cosole.log(students[i]) //{} {} {} 每一个对象
cosole.log(students[i].name) //小明 小红 小蓝
}
//渲染例子
for(let i=0;i<students.length;i++){
document.write(`
<tr>
<td>${i+1}</td>
<td>${students[i].name}</td>
<td>${students[i].age}</td>
<td>${students[i].gender}</td>
<td>${students[i].hometwon}</td>
</tr>
`)
}
for...in... 循环中,每一个迭代值是对应值的字符串形式。
2.5 内置对象
内置对象就是可以直接使用的对象,不需要使用字面量,Object以及构造函数创建的对象,js已经定义好的对象。
1、使用MDN(web开发文档网站)查询资料。
2、Math对象:是一个内置对象,主要用于数学运算的,不是一个函数对象(通过构造函数创建的对象叫函数对象),在创建Math对象时,不能使用new运算符(即不能new Math),
它的属性和方法在使用时采用:
Math.属性名
Math.方法名(参数)
(1)属性:
Math.PI:表示圆周率,一个圆的周长和直径之比,约等于 3.14159。
(2)方法:
a、Math.abs(x):返回参数x的绝对值
b、Math.floor(x):返回小于等于形参(给定参数)的最大整数,即一个数向下取整后的值。3.99,返回之后就是3。
c、Math.ceil(x):返回大于等于一个数的最小整数,即一个数向上取整后的值。3.99,返回之后的值就是4。
d、Math.max([x[,y[,...]]]):返回所有参数中的最大值。
e、Math.min([x[,y[,...]]]):返回所有参数中的最小值。
f、Math.pow(x,y):返回x的y次方。
g、Math.sqrt(x):返回x的算术平方根
h、Math.round(x):取整,x四舍五入以后的整数。
i、Math.random():返回0.0到1.0之间的随机数,包括0,不包括1。
j、Math.trunc():去除小数点后的所以有内容,没有四舍五入。
例子:
// 定义一个函数,用于生成min-max之间的随机数
//构造函数
// function Random() {
// this.getRandom=function(min,max){
// let num = Math.random()*(max - min) + min;
// return Math.round(num);
// }
// }
// let t = new Random()
// console.log(t.getRandom(10,100));
//普通函数
// function Random(min,max) {
// let num = Math.round(Math.random()*(max - min) + min);
// return num;
// }
// let t = Random(10,100);
// console.log(t);
//定义一个3*4的二维数组,数组元素随机生成,将数组显示出来,并输出数组。
//1、定义二维数组
let arr = new Array(new Array(4),new Array(4),new Array(4));
//2、随机生成二维数组中的元素,并显示
let str ='';
for (let i = 0; i < arr.length; i++) {//控制行
for (let j = 0; j < arr[i].length; j++) {
//构造函数
arr[i][j] =t.getRandom(10,100);
//普通函数
// arr[i][j] =Random(10,100);
str += arr[i][j]+'\t';
}
str += '\n';
}
console.log(str);
3、日期对象date
Date对象:是一个函数对象,,使用new运算符创建对象
(1)构造函数:
a、无参构造函数:new Date()使用的日期格式是:月日年
b、传入年月日、时分秒:new Date(年,月,日,时,分,秒),月份取值在0-11之间,0表示1月,11表示12月
c、传入字符串表示日期和时间:new Date('字符串')
d、传入一个整数:new Date(整数),整数代表毫秒数
(2)其他函数:
a、getFullYear():获取年份(年份四位)
b、getMonth():获取月份(0-11)
c、getDate():获取月份中的某一天(日期)(1-31)。
d、getDay():获取星期(0-6)0表示星期天。
e、getHours():获取小时数
f、getMinutes():获取分钟数
g、getSeconds():获取秒钟数;
h、getTime():获取1970年1月1日0时0分0秒到当前日期之间的毫秒数。
i、toLocaleDateString():方法返回该日期对象日期部分的字符串。(只有年月日)
j、toLocaleString(): 方法返回该日期对象的字符串。(年月日,时分秒都显示)
k、The toLocaleTimeString() :方法返回该日期对象时间部分的字符串(时分秒)
l、toTimeString() :方法以人类易读形式返回一个日期对象时间部分的字符串
三、String内置对象
1、String对象:字符串。用单引号或('')或双引号("")括起来的字符序列。
(1)创建方式:
a、字面量:' '或" "
b、使用构造函数:new String()
(2)字符串属性:length ------表示字符串的长度(字符串中字符的个数)
用法:字符串对象名.length
2、String对象的常用方法:字符串名.函数名(实参)
(1)charAt(index):返回字符串中,index位置上的字符。
返回下标为0的字符。index表示下标。
(2)charCodeAt(index)返回字符串中index位置上的字符的unicode编码。
ASCII码:是美国做的字符编码('a':97...)只支持英文字符,表示一个字符使用1个字节(byte),,即8个二进制位。
unicode码:国际标准化组织做的一套编码。表示一个字符使用2个字节, 支持中文。
ISO-8859-1码:不支持中文
GBK:支持中文
GB2312:支持简体中文
(3)concat(字符串):连接字符串,将两个及两个以上的字符串进行连接
concat可以连续拼接字符串。
(4)endsWith(子串):判断字符串是否以给定的子串结尾。
flag输出true或者false,s5输出剩余的字符。
(5)indexOf(子串):返回子串在字符串中首次出现的位置,返回下标
indexOf(子串,整数):返回从大于等于整数的位置开始查找子串第一次出现的位置。
(6)lastindexOf(子串):返回子串在字符串中最后出现的位置(下标)
(7)includes(子串):查找字符串中是否包含指定的子串。若包含返回true,不包含返回false。
(8)startsWith(子串):判断字符串是否以给定子串开头,是返回true,不是返回false。
(9)split(字符):将字符串分割成字符串数组。
(10)replace(oldstr,newstr):在字符串中查找oldstr第一次出现的位置,并用newstr替换它。
(11)stbstr(star,end):截取字符串中从start到end之间的字符串,不包含end。
(12)substtringr(star,end):截取start到end之间的子串,不包含end。
(13)trim():去掉字符串两端的空格。
(14)trimEnd():去掉字符串结尾的空白字符。
(15)trimStart():去掉字符串前面的空白字符。
(16)tolowerCase():将字符串中的所有字母转换为小写。
(17)toUPperCase():将字符串中的所有字母转换为大写字母。
(18)toString():将字符串对象转换成字符串,输出结果没有大括号括起,是一个普通的字符串。
(19)valueOf():将字符串对象转换成一个原始值。
四、字符串的不可变性:指当一个字符串被定义以后,它的内容是不变的。虽然通过调用相关函数看似改变了串的内容,实际是在内存中新开辟了一个空间存放新的串。
五、综合练习
三、对象的深浅克隆
3.1 复习基本类型值和引用类型值
还记得我们之前学习过的基本类型值和引用类型值吗?
| 举例 | 当 var a = b 变量传值时 | 当用 == 比较时 | 当用 === 比较时 | |
|---|---|---|---|---|
| 基本类型值 | 数字、字符串、布尔、undefined、null | 内存中产生新的副本 | 比较值是否相等 | 类型相等的前提下,比较值相等 |
| 引用类型值 | 对象、数组等 | 内存中不产生新的副本,而是让新变量指向同一个对象 | 比较内存地址是否相同,即比较是否为同一对象 | 比较内存地址是否相同,即比较是否为同一对象 |
对于引用类型的比较来说:== 与 === 是没有区别的!
var a = {};
var b = {};
var c = a;
console.log(a == b); // false
console.log(a === b); // false
console.log(a == c); // true
console.log(a === c); // true
3.2 对象是引用类型值
对象是引用类型值,这意味着:
不能用 var obj2 = obj1 这样的语法克隆一个对象。
使用 == 或者 === 进行对象的比较时,比较的是它们是否为内存中的同一个对象,而不是比较值是否相同。
【案例】
// 例子1
var obj1 = {
a: 1,
b: 2,
c: 3
};
var obj2 = {
a: 1,
b: 2,
c: 3
};
console.log(obj1 == obj2); // false
console.log(obj1 === obj2); // false
console.log({} == {}); // false
console.log({} === {}); // false
// 例子2
var obj3 = {
a: 10
};
var obj4 = obj3;
obj3.a++;
console.log(obj4); // {a: 11}
console.log(obj3 == obj4); // true
console.log(obj3 === obj4); // true
3.3 对象的浅克隆
复习什么是浅克隆:只克隆对象的 “表层”,如果对象的某些属性值又是引用类型值,则不进一步克隆它们,只是传递它们的引用。
使用 for...in... 循环即可实现对象的浅克隆。
【案例】
var obj1 = {
a: 1,
b: 2,
c: [44, 55, 66]
};
// var obj2 = obj1; 这不是克隆,千万不能这样!!!!
// 实现浅克隆
var obj2 = {};
for (var k in obj1) {
// 每遍历一个 k 属性,就给 obj2 也添加一个同名的 k 属性
// 值和 obj1 的 k 属性值相同
obj2[k] = obj1[k];
}
// 为什么叫浅克隆呢?比如 c 属性的值是引用类型值,那么本质上 obj1 和 obj2 的 c 属性是内存中的同一个数组,并没有被克隆分开。
obj1.c.push(77);
console.log(obj2); // obj2 的 c 属性这个数组也会被增加 77 数组
console.log(obj1.c == obj2.c); // true,true 就证明了数组是同一个对象
3.4 对象的深克隆
复习什么是深克隆:克隆对象的全貌,不论对象的属性值是否又是引用类型值,都能将它们实现克隆。
和数组的深克隆类似,对象的深克隆需要使用递归。
面试时经常会考察深克隆算法,必须掌握。
【案例】
var obj1 = {
a: 1,
b: 2,
c: [33, 44, {
m: 55,
n: 66,
p: [77, 88]
}]
};
// 深克隆
function deepClone(o) {
// 要判断 o 是对象还是数组
if (Array.isArray(o)) {
// 数组
var result = [];
for (var i = 0; i < o.length; i++) {
result.push(deepClone(o[i]));
}
} else if (typeof o == 'object') {
// 对象
var result = {};
for (var k in o) {
result[k] = deepClone(o[k]);
}
} else {
// 基本类型值
var result = o;
}
return result;
}
var obj2 = deepClone(obj1);
console.log(obj2);
console.log(obj1.c == obj2.c); // false
obj1.c.push(99);
console.log(obj2); // obj2 不变的,因为没有“藕断丝连”的现象
obj1.c[2].p.push(999);
console.log(obj2); // obj2 不变的,因为没有“藕断丝连”的现象