目录
⭐判断一个字符串,'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数
2.substr('截取的起始位置', '截取几个字符');
⭐有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 *
一、数组
1.1 数组的概念
数组是一组数据的集合,其中的每个数据被称作元素,在数组中可以存放任意类型的元素。
数组是一种将一组数据存储在单个变量名下的优雅方式。
1.2 创建数组
1.利用new创建数组
var 数组名 = new Array();
var arr = new Array(); //创建一个新的空数组
注意:
-
这种方式暂且了解,等学完对象再看
-
注意
Array()
,A要大写
2.利用数组字面量创建数组
// 使用数组字面量的方式创建空的数组
var 数组名 = [];
// 使用数组字面量方式创建带初始值的数组
var arr1 = [1, 2, 'pink老师', true];
注意:
- 数组里面可以放任意的数据类型
- 数组里面的数据用,分隔
- 数组里面的数据称为数组元素
- 这种方式是使用最多的方式
1.3 获取数组中的元素
数组的索引
索引(下标):用来访问数组元素的序号(数组下标从0开始)。
格式:数组名[索引号]
var arr2 = ['迪丽热巴', '古丽扎娜', '佟丽丫丫'];
console.log(arr2[0]);
console.log(arr2[1]);
console.log(arr2[2]);
console.log(arr2[3]); // 因为没有这个数组元素 所以输出的结果是 undefined
1.4 遍历数组
遍历:把数组中每个元素从头到尾访问一次。
<script>
// 遍历数组:就是把数组的元素从头到尾访问一次
var arr = ['red', 'green', 'blue'];
for (var i = 0; i < 3; i++) {
console.log(arr[i]);
}
// 1. 因为我们的数组索引号从0开始 ,所以 i 必须从 0开始 i < 3
// 2. 输出的时候 arr[i] i 计数器当索引号来用
</script>
1.5 获取数组长度
使用“数组名.length”可以访问数组元素的数量(数组长度)
<script>
// 数组长度 数组名.length
var arr = ['关羽', '张飞', '马超', '赵云', '黄忠', '刘备', '姜维', 'pink'];
for (var i = 0; i < 7; i++) {
console.log(arr[i]);
}
console.log(arr.length);
for (var i = 0; i < arr.length; i++) {
console.log(arr[i]);
}
// 1. 数组的长度是元素个数 不要跟索引号混淆
// 2. arr.length 动态监测数组元素的个数
</script>
- for 里面的 i 是计数器,当索引号使用,arr[i]是数组元素,第i个数组元素。
⭐数组求和及平均值
分析:
- 声明一个求和变量 sum。
- 遍历这个数组,把里面每个数组元素加到 sum 里面。
- 用求和变量 sum 除以数组的长度就可以得到数组的平均值。
<script>
var array = [2,6,1,7,4];
var sum = 0;
var avg = 0;
for (var i = 0; i < array.length; i++){
sum += array[i]; //我们加的是数组元素,不是计数器
}
avg = sum / array.length;
console.log(sum,avg);
</script>
⭐求数组最大值
<script>
var arr = [2,6,1,77,52,25,7];
var max =arr[0];
for (var i = 1; i < arr.length; i++){
if (arr[i] > max){
max = arr[i];
}
}
console.log(max);
</script>
⭐数组转换为分割字符串
要求:将数组['red','green','blue','pink']转换为字符串,并用|或其他分隔符分割
<script>
//需要一个新变量用于存放转换完的字符串str
//遍历原来的数组,分别把里面的数据取出来,加到字符串里面
//同时在后面多加一个分隔符
var arr = ['red','blue','green','pink'];
var str = '';
var sep = '|';
for (var i = 0; i < arr.length; i++){
str += arr[i] + sep ;
}
console.log(str);
alert(str);
</script>
1.6 数组中新增元素
可以通过修改length长度以及索引和增加数组元素。
1. 通过修改length长度新增数组元素
- 可以通过修改length长度来实现数组扩容的目的
- length属性是可读写的
2.通过修改数组索引新增数组元素
- 可以通过修改数组索引的方式追加数组元素
- 不能直接给数组名赋值,否则会覆盖掉以前的数据
<script>
// 1. 新增数组元素 修改length长度
var arr = ['red', 'green', 'blue'];
console.log(arr.length);
arr.length = 5; // 把我们数组的长度修改为了 5 里面应该有5个元素
console.log(arr);
console.log(arr[3]); // undefined
console.log(arr[4]); // undefined
// 2. 新增数组元素 修改索引号 追加数组元素
var arr1 = ['red', 'green', 'blue'];
arr1[3] = 'pink';
console.log(arr1);
arr1[4] = 'hotpink';
console.log(arr1);
arr1[0] = 'yellow'; // 这里是替换原来的数组元素
console.log(arr1);
arr1 = '有点意思';
console.log(arr1); // 不要直接给 数组名赋值 否则里面的数组元素都没有了
</script>
⭐数组新增元素
新建一个数组,里面存放10个整数(1-10)
分析:
- 使用循环来追加数组
- 声明一个空数组arr
- 循环中的计数器i 可以作为数组元素存入
- 由于数组的索引号是从0开始的,因此计数器从0开始更合适,存入的数据元素要加+1
var arr = [];
for (var i = 0; i < 100; i++) {
// arr = i; 不要直接给数组名赋值 否则以前的元素都没了
arr[i] = i + 1;
}
console.log(arr);
⭐筛选数组
要求:将数组[2,0,6,1,77,0,52,0,25,7]中大于等于10的元素选出来,放入新数组
<script>
//方法1
var arr = [2,0,6,1,77,0,52,0,25,7];
var newarr = [];
var j = 0;
for (var i = 0; i < arr.length; i++){
if (arr[i] > 10){
//新数组的索引号应该从0开始存
newarr[j] = arr[i];
j++;
}
}
console.log(newarr);
//方法2
var arr = [2,0,6,1,77,0,52,0,25,7];
var newarr = [];
// 刚开始的newarr.length为0,length会自动检测元素的变化
for (var i = 0; i < arr.length; i++){
if (arr[i] > 10){
//新数组的索引号应该从0开始存,依次递增
newarr[newarr.length] = arr[i];
j++;
}
}
console.log(newarr);
</script>
1.7 数组案例
⭐删除指定数组元素
要求:将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。
<script>
// 将数组[2, 0, 6, 1, 77, 0, 52, 0, 25, 7]中的 0 去掉后,形成一个不包含 0 的新数组。
// 1、需要一个新数组用于存放筛选之后的数据。
// 2、遍历原来的数组, 把不是 0 的数据添加到新数组里面(此时要注意采用数组名 + 索引的格式接收数据)。
// 3、新数组里面的个数, 用 length 不断累加。
var arr = [2, 0, 6, 1, 77, 0, 52, 0, 25, 7];
var newarr = [];
for (var i = 0; i< arr.length; i++){
if (arr[i] != 0){
newarr[newarr.length] = arr[i];
}
}
console.log(newarr);
</script>
⭐翻转数组
将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放
<script>
// 将数组 ['red', 'green', 'blue', 'pink', 'purple'] 的内容反过来存放
// 1、声明一个新数组 newArr
// 2、把旧数组索引号第4个取过来(arr.length - 1),给新数组索引号第0个元素 (newArr.length)
// 3、我们采取 递减的方式 i--
var arr = ['red', 'green', 'blue', 'pink', 'purple'];
var newarr = [];
for (var i = arr.length-1; i >= 0; i--){
newarr[newarr.length] = arr[i];
}
console.log(newarr);
</script>
⭐数组排序(冒泡排序)
冒泡排序:是一种算法,把一系列的数据按照一定的顺序进行排列的显示(从小到大或从大到小)
<script>
var arr = [5,4,3,2,1];
for (var i = 0; i <= arr.length-1; i++){ //外层循环管趟数
for (var j = 0; j < arr.length-i-1;j++){ //里层循环管每趟的交换次数
//内部交换两个变量的值 前一个和后面一个数组元素相比较
if (arr[j] > arr[j+1]){
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
console.log(arr);
</script>
二、函数
2.1 函数的概念
函数计算被封装了一段可以被重复执行调用的代码块。
目的:让大量代码重复使用。
2.2 函数的使用
函数在使用时分为两步:声明函数和调用函数。
1.声明函数
function 函数名() {
函数体
}
- function 声明函数的关键字 全部小写
- 函数是做某件事情,函数名一般是动词
- 函数不调用自己不执行(只声明函数不调用,函数不执行)
2.调用函数
函数名();
- 一定不要忘记小括号
2.3 函数的封装
函数的封装是把一个或者多个功能通过函数的方式封装起来,对外只提供一个简单的函数接口。
⭐利用函数计算1-100之间的累加和
<script>
//利用函数求1-100之间累加和
function getsum(){
var sum = 0;
for (var i = 1; i <= 100; i++){
sum +=i;
}
console.log(sum);
}
getsum();
</script>
2.4 函数的参数
我们可以利用函数的参数实现函数重复不同的代码。
1.形参(声明函数时)
function 函数名(形参1,形参2...) { // 在声明函数的小括号里面是 形参 (形式上的参数)
}
2.实参(调用函数时)
函数名(实参1,实参2...); // 在函数调用的小括号里面是实参(实际的参数)
3.形参和实参的执行过程
function cook(aru) { // 形参是接受实参的 aru = '酸辣土豆丝' 形参类似于一个变量
console.log(aru);
}
cook('酸辣土豆丝');
cook('大肘子');
函数的参数可以有也可以没有,个数不限
⭐利用函数求任意两个数的和
⭐利用函数求任意两个数之间的和
<script>
//1.利用函数求任意两个数的和
function getsum(num1,num2){
getsum = num1 + num2 ;
console.log(getsum);
}
getsum(1,2);
//2.利用函数求任意两个数之间的和(如求1-100之间数的和)
function getsum1(num3,num4){
var sum1=0;
for (var i = num3; i <= num4; i++){
sum1 += i;
}
console.log(parseInt(sum1));
}
getsum1(1,10);
</script>
注意点:
- 多个参数之间用逗号隔开
- 形参可以看做不用声明的变量
- 注意有些变量一定要初始化
4.函数形参和实参个数不匹配的问题
<script>
//函数形参实参个数匹配
function getsum(num1,num2){
console.log(num1 + num2);
}
//1.如果实参的个数和形参的个数一致,则正常输出结果
getsum(1,2);
//2.如果实参的个数多于形参的个数 会取到形参的个数
getsum(1,2,3);
//3.如果实参的个数小于形参的个数
//形参可以看做是不用声明的变量 num2是一个变量但是没有接受值
getsum(1);
</script>
5.小结
- 函数可以带参数也可以不带参数
- 声明函数的时候,函数名括号里面的是形参,形参的默认值为 undefined
- 调用函数的时候,函数名括号里面的是实参
- 多个参数中间用逗号分隔
- 形参的个数可以和实参个数不匹配,但是结果不可预计,我们尽量要匹配
2.5 函数的返回值
1.return语句
有的时候,我们会希望函数将值返回给调用者,此时通过使用return语句就可以实现
function 函数名() {
return 需要返回的结果;
}
函数名();
- 我们函数只是实现某种功能,最终的结果需要返回给函数的调用者函数名() 通过return 实现的
- 只要函数遇到return 就把后面的结果 返回给函数的调用者 函数名() = return后面的结果
注意事项:
- return后面的代码不会被执行
- return只能返回一个值,且返回的结果是最后一个值
- 若要返回多个值,可以采用数组
function getResult(num1, num2) {
return [num1 + num2, num1 - num2, num1 * num2, num1 / num2];
}
var re = getResult(1, 2); // 返回的是一个数组
console.log(re);
⭐求任意两个数的和
function getSum(num1, num2) {
return num1 + num2;
}
console.log(getSum(1, 2));
⭐利用函数求任意两个数的最大值(函数值)
<script>
function getmax (num1,num2) {
var max = 0;
if (num1 > num2){
max = num1;
} else {
max = num2;
}
return max;
}
console.log(getmax(2,6));
</script>
⭐求数组中的最大值(函数版)
两种输出方法都可以
<script>
function getarrmax(arr) {
var max = arr[0];
for ( var i = 1 ; i < arr.length; i++){
if (arr[i] > max){
max = arr[i];
}
}
return max;
}
// console.log(getarrmax([5,2,99,101,67,77]));
var re =getarrmax[5,2,99,101,67,77];
console.log(re);
2.函数没有 return 则返回 undefined
console.log(re);
// 4. 我们的函数如果有return 则返回的是 return 后面的值,如果函数么有 return 则返回undefined
function fun1() {
return 666;
}
console.log(fun1()); // 返回 666
function fun2() {
}
console.log(fun2()); // 函数返回的结果是 undefined
3.break,continue,return的区别
break
: 结束当前循环体(如 for、while)continue
:跳出本次循环,继续执行下次循环(如for、while)return
:不仅可以退出循环,还能够返回 return 语句中的值,同时还可以结束当前的函数体内的代码
2.6 arguments的使用
当我们不确定有多少个参数传递的时候,可以用 arguments 来获取。在 JavaScript 中,arguments 实际上它是当前函数的一个内置对象。所有函数都内置了一个 arguments 对象,arguments 对象中存储了传递的所有实参。
function fn() {
console.log(arguments);
}
fn(1,2,3);
arguments展示形式是一个伪数组,因此可以进行遍历。伪数组具有以下特点
- 具有 length 属性
- 按索引方式储存数据
- 不具有数组的 push , pop 等方法
只有函数才有 arguments 对象,而且是每个函数都内置好了这个arguments。
⭐利用函数求任意个数的最大值
<script>
function getmax() {
var max = arguments[0];
for (var i = 1; i < arguments.length; i++){
if (arguments[i] > max){
max = arguments[i];
}
}
return max;
}
console.log(getmax(1,2,3,4,5,6));
</script>
⭐利用函数封装方式翻转任意一个数组
<script>
//利用函数任意数组reverse翻转
function reverse(arr) {
var newArr = [];
for (var i = arr.length; i >= 0 ; i-- ){
newArr[newArr.length] = arr[i];
}
return newArr;
}
var arr1 =reverse([1,3,4,6,9]);
console.log(arr1);
</script>
⭐利用函数封装方式对数组排序--冒泡排序
<script>
function sort(arr) {
for (var i = 0; i < arr.length-1; i++){
for (var j =0; j < arr.length-i-1; j++){
if (arr[j] > arr[j+1]){
var temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
return arr;
}
var arr1 = sort([1,2,3,4,5]);
console.log(arr1);
</script>
⭐利用函数封装实现判断闰年
<script>
function isRunYear (year) {
var flag = false;
if (year % 4 == 0 && year % 100 !== 0 || year %400 == 0){
flag =true;
}
return flag;
}
console.log(isRunYear(2024));
</script>
⭐函数可以调用另外一个函数
因为每个函数都是独立的代码块,用于完成特殊任务,因此会经常用到函数相互调用的情况。
<script>
//函数是可以相互调用的
function fn1() {
console.log(11);
fn2();
}
fn1();
function fn2() {
console.log(22);
}
</script>
⭐用户输入年份,输出当前年份2月份的天数
如果是闰年,则2月份是29天,如果是平年,则二月份是28天
<script>
// 用户输入年份,输出当前年份2月份的天数
function backDay() {
var year = prompt('请您输入年份:');
if (isRunYear(year)) { // 调用函数需要加小括号
alert('当前年份是闰年2月份有29天');
} else {
alert('当前年份是平年2月份有28天');
}
}
backDay();
// 判断是否为闰年的函数
function isRunYear(year) {
// 如果是闰年我们返回 true 否则 返回 false
var flag = false;
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
flag = true;
}
return flag;
}
</script>
2.7 函数表达式声明函数的方式
<script>
// 函数的2中声明方式
// 1. 利用函数关键字自定义函数(命名函数)
function fn() {
}
fn();
// 2. 函数表达式(匿名函数)
// var 变量名 = function() {};
var fun = function(aru) {
console.log('我是函数表达式');
console.log(aru);
}
fun('pink老师');
// (1) fun是变量名 不是函数名
// (2) 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而 函数表达式里面存的是函数
// (3) 函数表达式也可以进行传递参数
</script>
- fun是变量名 不是函数名
- 函数表达式声明方式跟声明变量差不多,只不过变量里面存的是值 而函数表达式里面存的是函数
- 函数表达式也可以进行传递参数
三、JavaScript作用域
3.1 作用域概述
通常来说,一段程序代码中所用到的名字并不总是有效和可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域。作用域的使用提高了程序逻辑的局部性,增强了程序的可靠性,减少了名字冲突。
JavaScript的作用域(es6之前)有两种:
- 全局作用域
- 局部作用域
1.全局作用域
整个script标签 或者是一个单独的js文件
2.局部作用域(函数作用域)
在函数内部就是函数作用域,这个代码的名字只在函数内部起效果和作用。
function fn() {
// 局部作用域
}
3.2 变量的作用域
根据作用域的不同,我们变量分为全局变量和局部变量
1.全局变量
在全局作用域下声明的变量叫做全局变量(在函数外部定义的变量)
-
全局变量在代码的任何位置都可以使用
-
在全局作用域下 var 声明的变量 是全局变量
-
特殊情况下,在函数内不使用 var 声明的变量也是全局变量(不建议使用)
注意:如果在函数内部,没有声明直接赋值的变量也属于全局变量
2.局部变量
在局部作用域下的变量 或者说在函数内部的变量就是局部变量
-
局部变量只能在该函数内部使用
-
在函数内部 var 声明的变量是局部变量
-
函数的形参实际上就是局部变量
注意:函数的形参也可以看作是局部变量
注意:
全局变量只有浏览器关闭的时候才会销毁
3.全局变量和局部变量的区别
-
全局变量:在任何一个地方都可以使用,只有在浏览器关闭时才会被销毁,因此比较占内存
-
局部变量:只在函数内部使用,当其所在的代码块被执行时,会被初始化;当代码块运行结束后,就会被销毁,因此更节省内存空间
3.3 JavaScript中没有块级作用域
3.4 作用域链
-
只要是代码,就至少有一个作用域
-
写在函数内部的叫局部作用域
-
如果函数中还有函数,那么在这个作用域中就又可以诞生一个作用域
-
根据在内部函数可以访问外部函数变量的这种机制,用链式查找决定哪些数据能被内部函数访问,就称作作用域链(就近原则)
<script>
// 作用域链 : 内部函数访问外部函数的变量,采取的是链式查找的方式来决定取那个值 这种结构我们称为作用域链 就近原则
var num = 10;
function fn() { // 外部函数
var num = 20;
function fun() { // 内部函数
console.log(num);
}
fun();
}
fn();
</script>
⭐作用域链案例
function f1() {
var num = 123;
function f2() {
var num = 0;
console.log(num); // 站在目标出发,一层一层的往外查找
}
f2();
}
var num = 456;
f1();
//答案为123
var a = 1;
function fn1() {
var a = 2;
var b = '22';
fn2();
function fn2() {
var a = 3;
fn3();
function fn3() {
var a = 4;
console.log(a); //a的值 ?
console.log(b); //b的值 ?
}
}
}
fn1();
//a=4,b='22'
四、JavaScript预解析
4.1 预解析(面试常问)
JavaScript 代码是由浏览器中的 JavaScript 解析器来执行的。JavaScript 解析器在运行 JavaScript 代码的时候分为两步:预解析和代码执行。
1.预解析:
js引擎会把js里面所有的var 还有 function 提升到当前作用域的最前面
预解析分为:变量预解析(变量提升) 和 函数预解析(函数提升)
变量提升:就是把所有的变量声明提前到当前的作用域的最前面,不提升赋值操作
函数提升:就是把所有的函数声明提升到当前作用域的最前面, 不调用函数
2.代码执行:
按照代码书写的顺序从上到下执行
下面这一段代码很重要,注意理解里面的坑所在位置:
<script>
// 1问
console.log(num);
// 2问
console.log(num); // undefined 坑 1
var num = 10;
// 相当于执行了以下代码
// var num;
// console.log(num);
// num = 10;
// 3问
function fn() {
console.log(11);
}
fn();
// 4问
fun(); // 报错 坑2
var fun = function() {
console.log(22);
}
// 函数表达式 调用必须写在函数表达式的下面
// 相当于执行了以下代码
// var fun;
// fun();
// fun = function() {
// console.log(22);
// }
预解析案例
案例1
//案例1
var num = 10;
fun ();
function fun(){
console.log(num);
var num = 20;
}
//相当于执行了以下操作
var num;
function fun(){
var num;
console.log(num);
num = 20;
}
num = 10;
fun();
//结果是undefined
案例2
//案例2
var num = 10;
function fn() {
console.log(num);
var num = 20;
console.log(num);
}
fn();
//相当于执行了下面代码
var num;
function fn() {
var num;
console.log(num);
num = 20;
console.log(num);
}
num = 10;
fn();
// undefined 和 20
案例3
//案例3
var a = 18;
f1();
function f1() {
var b = 9;
console.log(a);
console.log(b);
var a = '123';
}
//相当于执行了下列代码
var a;
function f1() {
var b;
var a;
b = 9;
console.log(a);
console.log(b);
a = '123';
}
a = 18;
f1();
// unfined 和 9
案例4(面试常见混淆题)
//案例4
f1();
console.log(c);
console.log(b);
console.log(a);
function f1() {
var a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
//相当于执行了下列代码
function f1() {
var a;
//相当于 var a = 9; b = 9; c = 9; b和c直接赋值,没有var声明,当全局变量看
//集体声明 var a = 9, b = 9, c = 9; 注意上面和下面的逗号和分号
a = b = c = 9;
console.log(a);
console.log(b);
console.log(c);
}
f1();
console.log(c);
console.log(b);
console.log(a);
//结果是 9 9 9 9 9 报错
五、对象
5.1 对象
在 JavaScript 中,对象是一组无序的相关属性和方法的集合,所有的事物都是对象,例如字符串、数值、数组、函数等。
对象是由属性和方法组成的:
- 属性:事物的特征,在对象中用属性来表示(常用名词)
- 方法:事物的行为,在对象中用方法来表示(常用动词)
5.2 为什么需要对象
- 保存一个值时,可以用变量
- 保存多个值(一组值)时,可以用数组
- 保存一个人的完整信息 -----用对象
JS中的对象表达结构更清晰,更强大。
5.3 创建对象的三种方式
在 JavaScript 中,现阶段我们可以采用三种方式创建对象(object):
- 利用字面量创建对象
- 利用 new Object创建对象
- 利用构造函数创建对象
1.利用字面量创建对象
对象字面量:就是花括号{ }里面包含了这个具体事物(对象)的属性和方法。
{ }
里面采取键值对的形式表示
- 键:相当于属性名
- 值:相当于属性值,可以是任意类型的值(数字类型、字符串类型、布尔类型,函数类型等)
对象的调用
-
对象里面的属性调用 : 对象.属性名 ,这个小点 . 就理解为“ 的 ”
-
对象里面属性的另一种调用方式 : 对象[‘属性名’],注意方括号里面的属性必须加引号,我们后面会用
-
对象里面的方法调用:对象.方法名() ,注意这个方法名字后面一定加括号
<script>
// 1.利用对象字面量创建对象 {}
// var obj = {}; // 创建了一个空的对象
var obj = {
uname: '张三疯',
age: 18,
sex: '男',
sayHi: function() {
console.log('hi~');
}
}
// (1) 里面的属性或者方法我们采取键值对的形式 键 属性名 : 值 属性值
// (2) 多个属性或者方法中间用逗号隔开的
// (3) 方法冒号后面跟的是一个匿名函数
// 2. 使用对象
// (1). 调用对象的属性 我们采取 对象名.属性名 . 我们理解为 的
console.log(obj.uname);
// (2). 调用属性还有一种方法 对象名['属性名']
console.log(obj['age']);
// (3) 调用对象的方法 sayHi 对象名.方法名() 千万别忘记添加小括号
obj.sayHi();
</script>
变量、属性、函数、方法总结
-
变量:单独声明赋值,单独存在
-
属性:对象里面的变量称为属性,不需要声明,用来描述该对象的特征
-
函数:单独存在的,通过==“函数名()”==的方式就可以调用
-
方法:对象里面的函数称为方法,方法不需要声明,使用==“对象.方法名()”==的方式就可以调用,方法用来描述该对象的行为和功能。
2. 利用new object创建对象
创建格式:
var 对象名 = new Object();
<script>
//利用new object 创建对象
var obj = new Object(); //创建了一个空的对象
obj.uname = '张三丰';
obj.age = 18;
obj.sex = '男';
obj.sayHi = function() {
console.log('hi');
}
//我们是利用 等号 = 赋值的方法 添加对象的属性和方法
// 每个属性和方法之间用 分号结束
console.log(obj.uname);
console.log(obj.sex);
</script>
3.利用构造函数创建对象
构造函数 :是一种特殊的函数,主要用来初始化对象,即为对象成员变量赋初始值,它总与 new 运算符一起使用。我们可以把对象中一些公共的属性和方法抽取出来,然后封装到这个函数里面。
<script>
// 利用构造函数创建对象
// 我们需要创建四大天王的对象 相同的属性: 名字 年龄 性别 相同的方法: 唱歌
// 构造函数的语法格式
// function 构造函数名() {
// this.属性 = 值;
// this.方法 = function() {}
// }
// new 构造函数名();
function Star(uname, age, sex) {
this.name = uname;
this.age = age;
this.sex = sex;
this.sing = function(sang) {
console.log(sang);
}
}
var ldh = new Star('刘德华', 18, '男'); // 调用函数返回的是一个对象
// console.log(typeof ldh);
console.log(ldh.name);
console.log(ldh['sex']);
ldh.sing('冰雨');
var zxy = new Star('张学友', 19, '男');
console.log(zxy.name);
console.log(zxy.age);
zxy.sing('李香兰')
// 1. 构造函数名字首字母要大写
// 2. 我们构造函数不需要return 就可以返回结果
// 3. 我们调用构造函数 必须使用 new
// 4. 我们只要new Star() 调用函数就创建一个对象 ldh {}
// 5. 我们的属性和方法前面必须添加 this
</script>
4.构造函数和对象的区别
- 构造函数,如 Stars(),抽象了对象的公共部分,封装到了函数里面,它泛指某一大类(class)
- 创建对象,如 new Stars(),特指某一个,通过 new 关键字创建对象的过程我们也称为对象实例化
我们利用构造函数创建对象的过程就叫做对象的实例化。
5.new关键字执行过程
- new 构造函数可以在内存中创建了一个空的对象
- this 就会指向刚才创建的空对象
- 执行构造函数里面的代码 给这个空对象添加属性和方法
- 返回这个对象(所以构造函数里面不需要return)
6.遍历对象属性
for...in
语句用于对数组或者对象的属性进行循环操作
for(变量 in 对象名字){
// 在此执行代码
}
语法中的变量是自定义的,它需要符合命名规范,通常我们会将这个变量写为 k 或者 key。
<script>
// 遍历对象
var obj = {
name: 'pink老师',
age: 18,
sex: '男',
fn: function() {}
}
for (var k in obj) {
console.log(k); // k 变量 输出 得到的是 属性名
console.log(obj[k]); // obj[k] 得到是 属性值
}
// 我们使用 for in 里面的变量 我们喜欢写 k 或者 key
</script>
5.4 小结
- 对象可以让代码结构更加清晰
- 对象复杂数据类型object
- 本质:对象就是一组无序的相关属性和方法的集合。
- 构造函数泛指某一大类,比如苹果,不管是红色苹果还是绿色苹果,都统称为苹果
- 对象实例特指某一个事物,比如这个苹果,那个红苹果等等。
- for ... in 语句用于对对象的属性进行循环操作。
六、JavaScript内置对象
6.1 内置对象
-
JavaScript 中的对象分为3种:自定义对象 、内置对象、 浏览器对象
-
前面两种对象是JS基础内容,属于ECMAScript;第三个浏览器对象属于JS特有的
-
内置对象就是指 JS 语言自带的一些对象,这些对象供开发者使用,并提供了一些常用的或是最基本而必要的功能(属性和方法)
-
内置对象最大的优点就是帮助我们快速开发
-
JavaScript 提供了多个内置对象:Math、 Date 、Array、String等
6.2 查文档
常用文档MDN/W3C.
MDN:提供了有关开发网络技术(Open Web)的信息,包括HTML、CSS和万维网及HTML5应用的API。
网址:https://developer.mozilla.org/zh-CN/
查阅步骤:
1.查阅该方法的功能
2.查阅该方法的参数
3.查看返回值的意义及类型
- 带中括号[ ]表明中括号里面的参数是可以省略的。
4. 通过demo进行测试
6.3 Math
// Math数学对象 不是一个构造函数 ,所以我们不需要new 来调用 而是直接使用里面的属性和方法即可
console.log(Math.PI); // 一个属性 圆周率
console.log(Math.max(1, 99, 3)); // 99
console.log(Math.max(-1, -10)); // -1
console.log(Math.max(1, 99, 'pink老师')); // NaN
console.log(Math.max()); // -Infinity
⭐封装自己的数学对象
<script>
// 利用对象封装自己的数学对象 里面有 PI 最大值和最小值
var myMath = {
PI: 3.1415926,
max: function (){
var max = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] > max) {
max = arguments[i];
}
}
return max;
} ,
min : function (){
var min = arguments[0];
for (var i = 1; i < arguments.length; i++) {
if (arguments[i] < min) {
min = arguments[i];
}
}
return min;
}
}
console.log(myMath.PI);
console.log(myMath.max(1,4,9));
console.log(myMath.min(3,6,1));
</script>
1.abs,floor,ceil,round方法
<script>
// 1.绝对值方法
console.log(Math.abs(1));
console.log(Math.abs(-1));
console.log(Math.abs('-1'));//隐式转换 会把字符串型 -1 转换为数字型
console.log(Math.abs('pink'));//NaN
// 2.三个取整方法
//Math.floor() 向下取整 往小了取值
console.log(Math.floor(1.1));//1
console.log(Math.floor(1.9));//1
//Math.ceil() 向上取整 往大了取值
console.log(Math.ceil(1.1));//2
console.log(Math.ceil(1.9));//2
//Math.round() 四舍五入 但是 .5 特殊 它往大了取
console.log(Math.round(1.1));//1
console.log(Math.round(1.5));//2
console.log(Math.round(1.9));//2
console.log(Math.round(-1.1));//-1
console.log(Math.round(-1.5));//这个结果是-1
</script>
2.随机数方法 random( )
- 返回一个随机的小数 0 =< x <1
- 这个方法里面不跟参数
<script>
// 1.Math对象随机数方法 random() 返回一个随机的小数 0 =< x < 1
// 2. 这个方法里面不跟参数
// 3. 代码验证
console.log(Math.random());
// 4. 我们想要得到两个数之间的随机整数 并且 包含这2个整数
// Math.floor(Math.random() * (max - min + 1)) + min;
function getRandom(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
console.log(getRandom(1, 10));
// 5. 随机点名
var arr = ['张三', '张三丰', '张三疯子', '李四', '李思思', 'pink老师'];
// console.log(arr[0]);
console.log(arr[getRandom(0, arr.length - 1)]);
</script>
⭐猜数字游戏
<script>
// 猜数字游戏
// 1.随机生成一个1~10 的整数 我们需要用到 Math.random() 方法。
// 2.需要一直猜到正确为止,所以需要一直循环。
// 3.while 循环更简单
// 4.核心算法:使用 if else if 多分支语句来判断大于、小于、等于。
function getRandom(min,max){
return Math.floor(Math.random() * (max - min + 1)) + min;
}
var random = getRandom(1,10);
while (true) {
var num = prompt('你来猜,请输入1-10之间的数字');
if (num > random){
alert ('数字太大啦,请重新输入');
} else if (num < random) {
alert ('数字有点小哦,重新输入吧');
} else {
alert ('恭喜你猜对啦');
break;//退出整个循环,结束程序
}
}
</script>
6.4 日期对象
-
Date 对象和 Math 对象不一样,他是一个构造函数,所以我们需要实例化后才能使用
-
Date 实例用来处理日期和时间
<script>
// Date() 日期对象 是一个构造函数 必须使用new 来调用创建我们的日期对象
var arr = new Array(); // 创建一个数组对象
var obj = new Object(); // 创建了一个对象实例
// 1. 使用Date 如果没有参数 返回当前系统的当前时间
var date = new Date();
console.log(date);
// 2. 参数常用的写法 数字型 2019, 10, 01 或者是 字符串型 '2019-10-1 8:8:8'
var date1 = new Date(2022, 10, 1);
console.log(date1); // 返回的是 11月 不是 10月
var date2 = new Date('2022-01-23 8:8:8');
console.log(date2);
</script>
3.日期格式化
<script>
// 格式化日期 年月日
var date = new Date();
console.log(date.getFullYear()); // 返回当前日期的年 2019
console.log(date.getMonth() + 1); // 月份 返回的月份小1个月 记得月份+1 呦
console.log(date.getDate()); // 返回的是 几号
console.log(date.getDay()); // 3 周一返回的是 1 周六返回的是 6 但是 周日返回的是 0
// 我们写一个 2019年 5月 1日 星期三
var year = date.getFullYear();
var month = date.getMonth() + 1;
var dates = date.getDate();
var arr = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
var day = date.getDay();
console.log('今天是:' + year + '年' + month + '月' + dates + '日 ' + arr[day]);
</script>
⭐要求封装一个函数返回当前的时分秒 格式 08:08:08
<script>
// 格式化日期 时分秒
var date = new Date();
console.log(date.getHours()); // 时
console.log(date.getMinutes()); // 分
console.log(date.getSeconds()); // 秒
// 要求封装一个函数返回当前的时分秒 格式 08:08:08
function getTimer() {
var time = new Date();
var h = time.getHours();
h = h < 10 ? '0' + h : h;
var m = time.getMinutes();
m = m < 10 ? '0' + m : m;
var s = time.getSeconds();
s = s < 10 ? '0' + s : s;
return h + ':' + m + ':' + s;
}
console.log(getTimer());
</script>
4. 获取日期的总的毫秒形式
date.valueOf()
:得到现在时间距离1970.1.1总的毫秒数date.getTime()
:得到现在时间距离1970.1.1总的毫秒数
<script>
// 获得Date总的毫秒数(时间戳) 不是当前时间的毫秒数 而是距离1970年1月1号过了多少毫秒数
// 1. 通过 valueOf() getTime()
var date = new Date();
console.log(date.valueOf()); // 就是 我们现在时间 距离1970.1.1 总的毫秒数
console.log(date.getTime());
// 2. 简单的写法 (最常用的写法)
var date1 = +new Date(); // +new Date() 返回的就是总的毫秒数
console.log(date1);
// 3. H5 新增的 获得总的毫秒数
console.log(Date.now());
</script>
⭐京东倒计时案例
<script>
// 倒计时效果
// 1.核心算法:输入的时间减去现在的时间就是剩余的时间,即倒计时 ,但是不能拿着时分秒相减,比如 05 分减去25分,结果会是负数的。
// 2.用时间戳来做。用户输入时间总的毫秒数减去现在时间的总的毫秒数,得到的就是剩余时间的毫秒数。
// 3.把剩余时间总的毫秒数转换为天、时、分、秒 (时间戳转换为时分秒)
// 转换公式如下:
// d = parseInt(总秒数/ 60/60 /24); // 计算天数
// h = parseInt(总秒数/ 60/60 %24) // 计算小时
// m = parseInt(总秒数 /60 %60 ); // 计算分数
// s = parseInt(总秒数%60); // 计算当前秒数
function countDown(time) {
var nowTime = +new Date(); //返回当前时间总的毫秒数
var inputTime = +new Date(time);//返回的是用户输入时间总的毫秒数
var times = (inputTime - nowTime) / 1000; //time是剩余时间总的秒数
var d = parseInt(times/ 60 / 60 / 24);//天
d = d < 10 ? '0' + d : d;
var h = parseInt(times/ 60 / 60 %24);//时
h = h < 10 ? '0' + h : h;
var m = parseInt(times /60 %60 );//分
m = m < 10 ? '0' + m : m;
var s = parseInt(times%60);//当前的秒
s = s < 10 ? '0' + s : s;
return d + '天' + h + '时' + m + '分' + s + '秒';
}
console.log(countDown('2022-1-23 21:00:00'));
</script>
七、数组对象的创建
7.1 数组对象的创建
创建数组对象的两种方式
- 字面量方式
- new Array()
<script>
// 创建数组的两种方式
// 1. 利用数组字面量
var arr = [1,2,3];
console.log(arr[0]);
// 2. 利用new Array()
// var arr1 = new Array(); // 创建了一个空的数组
// var arr1 = new Array(2); // 这个2 表示 数组的长度为 2 里面有2个空的数组元素
var arr1 = new Array(2,3);//等价于 【2,3】 这样写表示 里面有2个数组元素,是2和3
console.log(arr1);
</script>
7.2 检测是否为数组
- instanceof 运算符,它可以用来检测是否为数组
- Array.isArray(参数); H5新增的方法 ie9以上版本支持
// 检测是否为数组
// (1) instanceof 运算符 它可以用来检测是否为数组
var arr = [];
var obj = {};
console.log(arr instanceof Array);
console.log(obj instanceof Array);
// (2) Array.isArray(参数); H5新增的方法 ie9以上版本支持
console.log(Array.isArray(arr));
console.log(Array.isArray(obj));
⭐翻转数组案例 使用判断数组事先判断
// 翻转数组
function reverse(arr) {
// if (arr instanceof Array) {
if (Array.isArray(arr)) {
var newArr = [];
for (var i = arr.length - 1; i >= 0; i--) {
newArr[newArr.length] = arr[i];
}
return newArr;
} else {
return 'error 这个参数要求必须是数组格式 [1,2,3]'
}
}
console.log(reverse([1, 2, 3]));
console.log(reverse(1, 2, 3));
7.3 添加删除数组元素的方法
1.添加元素push
push() 在我们数组的末尾 添加一个或者多个数组元素
var arr = [1, 2, 3];
// arr.push(4, 'pink');
console.log(arr.push(4, 'pink'));
console.log(arr);
//结果是[1, 2, 3, 4, 'pink']
- push 是可以给数组追加新的元素(在数组后面追加)
- push()参数直接写数组元素就可以了
- push完毕之后,返回的结果是 新数组的长度
- 原数组也会发生变化
2.添加元素unshift
unshift 在我们数组的开头 添加一个或者多个数组元素
var arr = [1, 2, 3,4,'pink'];
console.log(arr.unshift('red', 'purple'));
console.log(arr);
//结果是['red', 'purple', 1, 2, 3, 4, 'pink']
- unshift是在数组的前面追加新的元素
- unshift()参数直接写数组元素就可以了
- unshift完毕之后,返回的结果是 新数组的长度
- 原数组也会发生变化
3.删除元素pop
pop()它可以删除数组的最后一个元素
var arr = ['red', 'purple', 1, 2, 3, 4, 'pink']
console.log(arr.pop());
console.log(arr);
//结果是 ['red', 'purple', 1, 2, 3, 4]
- pop可以删除数组的最后一个元素 记住一次只能删除一个元素
- pop()没有参数
- pop完毕之后,返回的结果是 删除的那个元素
- 原数组也会发生变化
4.删除元素shift
shift()可以删除数组的第一个元素
var arr = ['red', 'purple', 1, 2, 3, 4];
console.log(arr.shift());
console.log(arr);
//结果是 ['purple', 1, 2, 3, 4]
- shift可以删除数组的第一个元素 记住一次只能删除一个元素
- shift()没有参数
- shift完毕之后,返回的结果是 第一个元素的值
- 原数组也会发生变化
⭐⭐筛选数组
有一个包含工资的数组[1500,1200,2000,2100,1800],要求把数组中工资超过2000的删除,剩余的放到新数组里面
<script>
// 有一个包含工资的数组[1500, 1200, 2000, 2100, 1800],要求把数组中工资超过2000的删除,剩余的放到新数组里面
var arr = [1500, 1200, 2000, 2100, 1800];
var newArr = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] < 2000) {
// newArr[newArr.length] = arr[i];
newArr.push(arr[i]);
}
}
console.log(newArr);
</script>
7.4 数组排序
var arr = ['pink', 'red', 'blue'];
arr.reverse();
console.log(arr);
var arr1 = [13, 4, 77, 1, 7];
arr1.sort(function(a, b) {
// return a - b; 升序的顺序排列
return b - a; // 降序的顺序排列
});
console.log(arr1);
7.5 数组索引的方法
1.indexOf 获取索引
作用:返回该数组元素的索引号,从前面开始查找
只返回第一个满足条件的索引号。
它如果在该数组里面找不到元素,则返回的是 -1
var arr = ['red', 'green', 'pink'];
console.log(arr.indexOf('blue'));
2.lastIndexOf
作用:返回该数组元素的索引号,从后面开始查找
var arr = ['red', 'green', 'blue', 'pink', 'blue'];
console.log(arr.lastIndexOf('blue')); // 4
⭐⭐数组去重(重点案例)
数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 要求去除数组中重复的元素。
<script>
// 数组去重 ['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] 要求去除数组中重复的元素。
// 1.目标: 把旧数组里面不重复的元素选取出来放到新数组中, 重复的元素只保留一个, 放到新数组中去重。
// 2.核心算法: 我们遍历旧数组, 然后拿着旧数组元素去查询新数组, 如果该元素在新数组里面没有出现过, 我们就添加, 否则不添加。
// 3.我们怎么知道该元素没有存在? 利用 新数组.indexOf(数组元素) 如果返回时 - 1 就说明 新数组里面没有改元素
// 封装一个 去重的函数 unique 独一无二的
function unique(arr){
var newArr = [];
for (var i = 0; i < arr.length; i++){
if (newArr.indexOf(arr[i]) === -1){
newArr.push(arr[i]);
}
}
return newArr;
}
var demo = unique(['c', 'a', 'z', 'a', 'x', 'a', 'x', 'c', 'b'] ) ;
console.log(demo);
</script>
7.6 数组转化为字符串
1.toString()
// 数组转换为字符串
// 1. toString() 将我们的数组转换为字符串
var arr = [1, 2, 3];
console.log(arr.toString()); // 1,2,3
2.join('分隔符')
// 2. join(分隔符)
var arr1 = ['green', 'blue', 'pink'];
console.log(arr1.join()); // green,blue,pink
console.log(arr1.join('-')); // green-blue-pink
console.log(arr1.join('&')); // green&blue&pink
3.数组中常用其他内置对象 
八、字符串类型
8.1 基本包装类型
就是把 简单数据类型 包装成为了 复杂数据类型,这样基本数据类型就有了属性和方法。
为了方便操作基本数据类型,JavaScript还提供了三个特殊的引用类型:String,Number和Boolean。
<script>
// 基本包装类型
var str = 'andy';
console.log(str.length);
// 对象 才有 属性和方法 复杂数据类型才有 属性和方法
// 简单数据类型为什么会有length 属性呢?
// 基本包装类型: 就是把简单数据类型 包装成为了 复杂数据类型
// (1) 把简单数据类型包装为复杂数据类型
var temp = new String('andy');
// (2) 把临时变量的值 给 str
str = temp;
// (3) 销毁这个临时变量
temp = null;
</script>
8.2 字符串的不可变
指的是里面的值不可变,虽然看上去可以改变内容,但其实是地址变了,内存中开辟了一个内存空间。
<script>
// 字符串的不可变性
var str = 'andy';
console.log(str);
str = 'red';
console.log(str);
// 因为我们字符串的不可变所以不要大量的拼接字符串
var str = '';
for (var i = 1; i <= 100; i++) {
str += i;
}
console.log(str);
</script>
8.3 根据字符返回位置
字符串中所有的方法,都不会修改字符串本身(字符串本身是不可变的),操作完成会返回一个新的字符串。
// 字符串对象 根据字符返回位置 str.indexOf('要查找的字符', [起始的位置])
var str = '改革春风吹满地,春天来了';
console.log(str.indexOf('春'));
console.log(str.indexOf('春', 3)); // 从索引号是 3的位置开始往后查找
⭐返回字符位置 (经典面试题)
查找字符串"abcoefoxyozzopp"中所有o出现的位置以及次数.
代码思路:
var str = "abcoefoxyozzopp";
var index = str.indexOf('o');
var num = 0;
while (index !== -1){
console.log(index);
num++;
index = str.indexOf('o',index + 1);
}
console.log('o出现的次数是:' + num);
8.4 根据位置返回字符(重点)
1.charAt(index)
根据位置返回字符
// 1. charAt(index) 根据位置返回字符
var str = 'andy';
console.log(str.charAt(3));
// 遍历所有的字符
for (var i = 0; i < str.length; i++) {
console.log(str.charAt(i));
}
2.charCodeAt(index)
获取指定位置处字符的ASCII码(index索引号)
常用于判断用户按了哪个键。
// 2. charCodeAt(index) 返回相应索引号的字符ASCII值 目的: 判断用户按下了那个键
console.log(str.charCodeAt(0)); // 97
3. str[index]
// 3. str[index] H5 新增的
console.log(str[0]); // a
8.5 判断对象中是否有某个属性
// 有一个对象 来判断是否有该属性 对象['属性名']
var o = {
age: 18
}
if (o['sex']) {
console.log('里面有该属性');
} else {
console.log('没有该属性');
}
⭐判断一个字符串,'abcoefoxyozzopp' 中出现次数最多的字符,并统计其次数
8.6 字符串操作方法(重点)
1.concat('字符串1','字符串2'....)
// 1. concat('字符串1','字符串2'....)
var str = 'andy';
console.log(str.concat('red'));
//andyred
2.substr('截取的起始位置', '截取几个字符');
var str1 = '改革春风吹满地';
console.log(str1.substr(2, 2)); // 第一个2 是索引号的2 从第几个开始 第二个2 是取几个字符
// 春风
8.7 替换字符replace
replace('被替换的字符', '替换为的字符') 它只会替换第一个字符
var str = 'andyandy';
console.log(str.replace('a', 'b'));
⭐有一个字符串 'abcoefoxyozzopp' 要求把里面所有的 o 替换为 *
var str1 = 'abcoefoxyozzopp';
while (str1.indexOf('o') !== -1) {
str1 = str1.replace('o', '*');
}
console.log(str1);
8.8 字符转换为数组 split('分隔符')
前面我们学过join把数组转换为字符串
var str2 = 'red, pink, blue';
console.log(str2.split(','));
var str3 = 'red&pink&blue';
console.log(str3.split('&'));
九、JavaScript中的简单数据类型和复杂数据类型
9.1 简单类型和复杂类型
简单类型又叫做基本数据类型或者值类型,复杂类型又叫做引用类型。
值类型:简单数据类型/基本数据类型,在存储时变量中存储的是值本身,因此叫做值类型
string ,number,boolean,undefined,null
引用类型:复杂数据类型,在存储时变量中存储的仅仅是地址(引用),因此叫做引用数据类型
通过 new 关键字创建的对象(系统对象、自定义对象),如 Object、Array、Date等
特殊:
// 简单数据类型 null 返回的是一个空的对象 object
var timer = null;
console.log(typeof timer);
- 如果有个变量我们以后打算存储为对象,暂时没想好放啥, 这个时候就给 null
9.2 堆和栈
堆栈空间分配区别:
- 栈(操作系统):由操作系统自动分配释放存放函数的参数值、局部变量的值等。
- 其操作方式类似于数据结构中的栈;
- 简单数据类型存放到栈里面
- 堆(操作系统):存储复杂类型(对象),一般由程序员分配释放
- 若程序员不释放,由垃圾回收机制回收。
- 复杂数据类型存放到堆里面
JavaScript中没有堆栈的概念,通过堆栈的方式,可以让大家更容易理解代码的一些执行方式,便于将来学习其他语言。
9.3 简单类型的内存分配
- 值类型(简单数据类型): string ,number,boolean,undefined,null
- 值类型变量的数据直接存放在变量(栈空间)中
1. 简单数据类型 是存放在栈里面 里面直接开辟一个空间存放的是值
2. 复杂数据类型 首先在栈里面存放地址 十六进制表示 然后这个地址指向堆里面的数据
9.4 简单类型传参
函数的形参也可以看做是一个变量,当我们把一个值类型变量作为参数传给函数的形参时,其实是把变量在栈空间里的值复制了一份给形参,那么在方法内部对形参做任何修改,都不会影响到的外部变量。
// 简单数据类型传参
function fn(a) {
a++;
console.log(a);
}
var x = 10;
fn(x);
console.log(x);
9.5 复杂类型传参
函数的形参也可以看做是一个变量,当我们把引用类型变量传给形参时,其实是把变量在栈空间里保存的堆地址复制给了形参,形参和实参其实保存的是同一个堆地址,所以操作的是同一个对象。
<script>
// 复杂数据类型传参
function Person(name) {
this.name = name;
}
function f1(x) { // x = p
console.log(x.name); // 2. 这个输出什么 ? 刘德华
x.name = "张学友";
console.log(x.name); // 3. 这个输出什么 ? 张学友
}
var p = new Person("刘德华");
console.log(p.name); // 1. 这个输出什么 ? 刘德华
f1(p);
console.log(p.name); // 4. 这个输出什么 ? 张学友
</script>