目录
[代码示例: 给定一个数组, 把数组中的奇数放到一个 newArr 中.](#代码示例: 给定一个数组, 把数组中的奇数放到一个 newArr 中.)
1) 如果实参个数比形参个数多, 则多出的参数不参与函数运算 如果实参个数比形参个数多, 则多出的参数不参与函数运算)
2) 如果实参个数比形参个数少, 则此时多出来的形参值为 undefined 如果实参个数比形参个数少, 则此时多出来的形参值为 undefined)
[2.使用new Object创建对象](#2.使用new Object创建对象)
3.JavaScript对象没有private/public等访问控制机制
[static 关键字](#static 关键字)
书接上文:前端基础------JavaScript(基础语法)(上篇)~~
数组
JavaScript 中的数组和 Java 中的数组还是有一定差异的~~
创建数组
闲聊:回忆一下在 Java 中数组的创建方式~~
int\[\] array={1,2,3};
int\[\] array=new int3;
int\[\] array=new int\[\]{1,2,3};
使用 new 关键字创建
javascript// Array 的 A 要大写 var arr = new Array();使用字面量方式创建 常用
javascriptvar arr = []; var arr2 = [1, 2, 'haha', false]; // 数组中保存的内容称为 "元素"注意 : JS 的数组不要求元素是相同类型.
这一点和 C, C++, Java 等静态类型的语言差别很大. 但是 Python, PHP 等动态类型语言也是如此
获取数组元素
使用下标的方式访问数组元素(从 0 开始)(和 Java 一样~~)
javascriptvar arr = ['小猪佩奇', '小猪乔治', '小羊苏西']; console.log(arr); console.log(arr[0]); console.log(arr[1]); console.log(arr[2]); arr[2] = '小猫凯迪'; console.log(arr);代码展示👇
javascriptlet array=new Array(); let array1=[1,2,3,"4"] console.log(array1)效果展示👇
如果下标超出范围读取元素, 则结果为 undefined
javascriptconsole.log(arr[3]); // undefined console.log(arr[-1]); // undefined注意 : 不要给数组名直接赋值, 此时数组中的所有元素都没了
相当于本来 arr 是一个数组, 重新赋值后变成字符串了
javascriptvar arr = ['小猪佩奇', '小猪乔治', '小羊苏西']; arr = '小猫凯迪';代码展示👇
javascriptlet array=new Array(); let array1=[1,2,3,"4"] console.log(typeof(array1)) console.log(array1) console.log(array1[2]) //这个代码放到 Java 中,会抛出一个数组越界的异常,但是在这里却是 undefined console.log(array1[10]) console.log(array1[-10]) array1="小比特" console.log(typeof(array1)) console.log(array1)效果展示👇
新增数组元素
在 Java 中我们需要先将数组转换成 List,再 add 去添加,然后再转换回数组,但是在 JavaScript 就没有这么麻烦了~~
1.通过修改length新增
相当于在末尾新增元素. 新增的元素默认值为 undefined
javascriptvar arr = [9, 5, 2, 7]; arr.length = 6; console.log(arr); console.log(arr[4], arr[5]);代码展示👇
javascriptlet array=[1,2,3,4] array.length = 10; console.log(array) array[7] = 8 console.log(array) console.log(array[9])效果展示👇
2.通过下标新增
如果下标超出范围赋值元素, 则会给指定位置插入新元素
javascriptvar arr = [];arr[2] = 10;console.log(arr)此时这个数组的 0 和 1 都是 undefined
代码展示👇
javascriptlet array = new Array() console.log(array) for(i=0;i<10;i++) array[i]=i; array[20] = 20 console.log(array)效果展示👇
3.使用push进行追加元素
代码示例 **:**给定一个数组, 把数组中的奇数放到一个 newArr 中.
javascriptvar arr = [9, 5, 2, 7, 3, 6, 8]; var newArr = []; for (var i = 0; i < arr.length; i++) { if (arr[i] % 2 != 0) { newArr.push(arr[i]); } } console.log(newArr);效果展示👇
删除数组中的元素
使用 splice 方法删除元素
javascriptvar arr = [9, 5, 2, 7]; // 第一个参数表示从下表为 2 的位置开始删除. 第二个参数表示要删除的元素个数是 1 个 arr.splice(2, 1); console.log(arr); // 结果 [9, 5, 7]效果展示👇
目前咱们已经用到了数组中的一些属性和方法.
arr.length, length 使用的时候不带括号, 此时 length 就是一个普通的变量(称为成员变量, 也叫属性)
arr.push(), arr.splice() 使用的时候带括号, 并且可以传参数, 此时是一个函数 (也叫做方法)
函数
语法格式
javascript// 创建函数/函数声明/函数定义 function 函数名(形参列表) { 函数体 return 返回值; } // 函数调用 函数名(实参列表) // 不考虑返回值 返回值 = 函数名(实参列表) // 考虑返回值函数定义并不会执行函数体内容, 必须要调用才会执行. 调用几次就会执行几次关于参数个数
javascript//定义没有参数列表,也没有返回值的一个函数 function hello() { console.log("hello"); } // 如果不调用函数, 则没有执行打印语句 hello();效果展示👇
代码展示👇
javascript//定义一个有参数,没有返回值的一个函数 function HelloXiaobite(num,name){ console.log(num + "Hello" + name) } HelloXiaobite(1,"CoderYanger")效果展示👇
代码展示👇
javascriptfunction hello() { console.log("hello"); } //定义一个有参数,有返回值的一个函数 function HelloXiaobite(num,name){ console.log(num + "Hello" + name) return 1; } let b = hello(); console.log(typeof(b)) let a = HelloXiaobite(1,"CoderYanger") console.log(typeof(a))效果展示👇
函数的返回值类型就是 return 的类型,这也恰好验证了 JavaScript 是一个动态语言的这个特性了~~
调用函数的时候进入函数内部执行, 函数结束时回到调用位置继续执行. 可以借助调试器来观察.
函数的定义和调用的先后顺序没有要求. (这一点和变量不同, 变量必须先定义再使用)
javascript// 调用函数 hello(); // 定义函数 function hello() { console.log("hello"); }
关于参数个数
实参和形参之间的个数可以不匹配. 但是实际开发一般要求形参和实参个数要匹配
1) 如果实参个数比形参个数多, 则多出的参数不参与函数运算
javascriptsum(10, 20, 30); // 30代码展示👇
javascript//定义一个有参数,有返回值的一个函数 function HelloXiaobite(num,name){ console.log(num + ",Hello," + name) return 1; } //实参个数比形参个数多 HelloXiaobite(1,"CoderYanger",3)效果展示👇
2) 如果实参个数比形参个数少, 则此时多出来的形参值为 undefined
javascriptsum(10); // NaN, 相当于 num2 为 undefined.代码展示👇
javascript//定义一个有参数,有返回值的一个函数 function HelloXiaobite(num,name){ console.log(num + ",Hello," + name) return 1; } //实参个数比形参个数少 HelloXiaobite();效果展示👇
JS 的函数传参比较灵活, 这一点和其他语言差别较大. 事实上这种灵活性往往不是好事
函数表达式
代码展示👇
javascriptfunction HelloXiaobite(num,name){ console.log(num + ",Hello," + name) return 1; } let result = function Sum(){ //计算1~100之间的和 ret=0; for(i=0;i<=100;i++) ret+=i return ret } console.log(result())效果展示👇
另外一种函数的定义方式
javascriptvar add = function() { var sum = 0; for (var i = 0; i < arguments.length; i++) { sum += arguments[i]; } return sum; } console.log(add(10, 20)); // 30 console.log(add(1, 2, 3, 4)); // 10 console.log(typeof add); // function此时形如 function() { } 这样的写法定义了一个匿名函数, 然后将这个匿名函数用一个变量来表示.
后面就可以通过这个 add 变量来调用函数了.
代码展示👇
javascriptlet b = function(){ //通过 arguments 可以打印调用参数列表 console.log(arguments) } b(); b(1,2,3)效果展示👇
可见传参数之前长度是 0,传参数之后长度就变成 3 了
JS 中函数是一等公民, 可以用变量保存, 也可以作为其他函数的参数或者返回值
作用域
某个标识符名字在代码中的有效范围.
在 ES6 标准之前, 作用域主要分成两个
全局作用域: 在整个 script 标签中, 或者单独的 js 文件中生效.
局部作用域/函数作用域: 在函数内部生效,这一点和 Java 还是非常大的~~
javascript// 全局变量 let num = 10; console.log(num); function test() { // 局部变量 let num = 20; console.log(num); } function test2() { // 局部变量 let num = 30; console.log(num); } test(); test2(); console.log(num); // 执行结果 10 20 30 10以上这种写法在 Java 中是不支持的,但是在 JavaScript 中就可以支持,效果展示👇
类似的,下面这段代码在 Java 中同样不支持,但是在 JavaScript 中却可以正常运行,代码展示👇
javascriptfor(i = 1;i <= 100; i++){ } console.log(i)效果展示👇
创建变量时如果不写 var、let, 此时这个变量就是一个全局变量
代码展示👇
javascriptfor(let i = 1;i <= 100; i++){ } console.log(i)效果展示👇
另外, 很多语言的局部变量作用域是按照代码块(大括号)来划分的, JS 在 ES6 之前不是这样的
javascriptif (1 < 2) { var a = 10; } console.log(a);
作用域链
背景:
函数可以定义在函数内部
内层函数可以访问外层函数的局部变量.
内部函数可以访问外部函数的变量. 采取的是链式查找的方式. 从内到外依次进行查找
javascriptlet num=10 function test01(){ let num=100 //100 console.log(num) function test02(){ let num=200 //200 console.log(num) } test02() } test01()效果展示👇
如果我们把 test02() 中的 num 注释掉之后,num 会从内往外找,结果找到 test01() 中的 num ,值为 100,代码展示👇
javascriptlet num=10 function test01(){ let num=100 //100 console.log(num) function test02(){ //let num=200 //200 //此时找到上面的 num,值为 100 console.log(num) } test02() } test01()效果展示👇
执行 console.log(num) 的时候, 会现在 test2 的局部作用域中查找 num. 如果没找到, 则继续去 test1 中查找. 如果还没找到, 就去全局作用域查找
类似的,如果我们把 test01() 中的 num 也注释掉,那么它在找的时候就会找到 全局变量的 num,值为 10,代码展示👇
javascriptlet num=10 function test01(){ //let num=100 //100 //此时找到的是上面的全局变量 10 console.log(num) function test02(){ console.log(num) } test02() } test01()效果展示👇
那么如果我们把全局变量的 num 也注释掉呢??直接给出效果展示👇
我们发现实在找不到的时候给出的提示是未定义~~
总的来说,作用域链就相当于在函数体内部去调用一个变量的时候,首先在我们自己的函数体内部去找,如果找到了,直接使用,没找到,就从我们这个函数的上一层函数里面去找我们的变量,还没找到,就从上上一层去找,直到找到全局变量为止,如果全局变量还没有,就会报错了~~
对象
有了 Java 的基础,我们理解"对象"就非常轻松了~~
基本概念
对象是指一个具体的事物
"电脑" 不是对象, 而是一个泛指的类别. 而 "我的联想笔记本" 就是一个对象
在 JS 中, 字符串, 数值, 数组, 函数都是对象
每个对象中包含若干的属性和方法.属性: 事物的特征.
方法: 事物的行为.
例如, 你有一个女票.
她的身高体重三围这些都是属性.
她的唱歌, 跳舞, 暖床都是方法
对象需要保存的属性有多个, 虽然数组也能用于保存多个数据, 但是不够好.例如表示一个学生信息. (姓名蔡徐坤, 身高 175cm, 体重 170斤)
var student = '蔡徐坤', 175, 170;
但是这种情况下到底 175 和 170 谁表示身高, 谁表示体重, 就容易分不清
JavaScript 的对象 和 Java 的对象概念上基本一致. 只是具体的语法表项形式差别较大
1.使用字面量创建对象常用
使用 { } 创建对象
javascriptlet a = {}; // 创建了一个空的对象,只不过它没有属性和方法 let student = { name: 'CoderYanger', height: 180, weight: 120, sayHello: function() { console.log("hello"); } }; //此时这个 student 就有了它的属性和方法 console.log(student.name)//第一种访问方式 console.log(student['height'])//第二种访问方式 console.log(student['weight']) //因为 sayHello 是通过匿名函数实现的,所以需要跟上() student.sayHello()效果展示👇
使用 { } 创建对象
属性和方法使用键值对的形式来组织.
键值对之间使用 , 分割. 最后一个属性后面的 , 可有可无
键和值之间使用 : 分割.
方法的值是一个匿名函数
使用对象的属性和方法:
javascript// 1. 使用 . 成员访问运算符来访问属性 `.` 可以理解成 "的" console.log(student.name); // 2. 使用 [ ] 访问属性, 此时属性需要加上引号 console.log(student['height']); // 3. 调用方法, 别忘记加上 () student.sayHello();
2.使用new Object创建对象
javascriptlet student = new Object(); // 和创建数组类似 student.name = "CoderYanger"; student.height = 181; student['weight'] = 120; student.sayHello = function () { console.log("hello"); } console.log(student.name); console.log(student['weight']); student.sayHello();效果展示👇
注意, 使用 { } 创建的对象也可以随时使用 student.name = "CoderYanger"; 这样的方式来新增属性
代码展示👇
javascriptlet student = {} student.name = "CoderYanger"; student.height = 181; student['weight'] = 120; student.sayHello = function () { console.log("hello"); } console.log(student.name); console.log(student['weight']); student.sayHello();效果展示👇
3.使用构造函数创建对象
前面的创建对象方式只能创建一个一个的对象 . 而使用构造函数可以很方便 的创建 多个对象.
在 Java 中,如何去创建对象呢??我们会先去写一个 class,然后通过这个 class 去创建我们每一个对象
但是在 ES6 之前,我们是没有 class 的,那么如果我们想创建批量对象的话怎么办呢??
此时我们就引入了"构造函数",通过构造函数可以创建出来多个对象
例如: 创建几个猫咪对象
javascriptvar mimi = { name: "咪咪", type: "中华田园喵", miao: function () { console.log("喵"); } }; var xiaohei = { name: "小黑", type: "波斯喵", miao: function () { console.log("猫呜"); } } var ciqiu = { name: "刺球", type: "金渐层", miao: function () { console.log("咕噜噜"); } }代码展示👇
javascriptfunction People(name,height,weight){ this.name = name this.height=height this.weight=weight this.Say = function(){ console.log(name + "say hello") } } let xiaoming = new People("小明",175,75) let CoderYanger = new People("CoderYanger",175,75) console.log(xiaoming) xiaoming.Say() console.log(CoderYanger) CoderYanger.Say()效果展示👇
此时写起来就比较麻烦. 使用构造函数可以把相同的属性和方法的创建提取出来, 简化开发过程
基本语法
javascriptfunction 构造函数名(形参) { this.属性 = 值; this.方法 = function... } var obj = new 构造函数名(实参);注意 :
在构造函数内部使用 this 关键字来表示当前正在构建的对象.
构造函数的函数名首字母一般是大写的.
构造函数的函数名可以是名词.
构造函数不需要 return
创建对象的时候必须使用 new 关键字
this 相当于 "我"
使用构造函数重新创建猫咪对象
javascriptfunction Cat(name, type, sound) { this.name = name; this.type = type; this.miao = function () { console.log(sound); // 别忘了作用域的链式访问规则 } } var mimi = new Cat('咪咪', '中华田园喵', '喵'); var xiaohei = new Cat('小黑', '波斯喵', '猫呜'); var ciqiu = new Cat('刺球', '金渐层', '咕噜噜'); console.log(mimi); mimi.miao();
理解new关键字
new 的执行过程:
先在内存中创建一个空的对象 { }
this 指向刚才的空对象(将上一步的对象作为 this 的上下文)
执行构造函数的代码, 给对象创建属性和方法
返回这个对象 (构造函数本身不需要 return, 由 new 代劳了)
参考 https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Operators/new
JavaScript的对象和Java对象的区别
1.JavaScript没有"类"的概念
对象其实就是 "属性" + "方法" .
类相当于把一些具有共性的对象的属性和方法单独提取了出来, 相当于一个 "月饼模子"
在 JavaScript 中的 "构造函数" 也能起到类似的效果.
而且即使不是用构造函数, 也可以随时的通过 { } 的方式指定出一些对象
在 ES6 中也引入了 class 关键字, 就能按照类似于 Java 的方式创建类和对象了
2.JavaScript对象不区分"属性"和"方法"
JavaScript 中的函数是 "一等公民", 和普通的变量一样. 存储了函数的变量能够通过 ( ) 来进行调用执行
3.JavaScript对象没有private/public等访问控制机制
对象中的属性都可以被外界随意访问.
4.JavaScript对象没有继承
没有 class 也就没有继承~~
继承本质就是 "让两个对象建立关联". 或者说是让一个对象能够重用另一个对象的属性/方法.
JavaScript 中使用 "原型" 机制实现类似的效果.
例如: 创建一个 cat 对象和 dog 对象, 让这两个对象都能使用 animal 对象中的 eat 方法.
通过 proto 属性来建立这种关联关系 (proto 翻译作 "原型")
当eat方法被调用的时候,先在自己的方法列表中寻找, 如果找不到,就去找原型中的方法, 如果原型中找不到, 就去原型的原型中去寻找...... 最后找到Object那里, 如果还找不到, 那就是未定义了。
关于原型链的内容比较复杂, 此处不做过多讨论
5.JavaScript没有"多态"
多态的本质在于 "程序猿不必关注具体的类型, 就能使用其中的某个方法".
C++ / Java 等静态类型的语言对于类型的约束和校验比较严格. 因此通过 子类继承父类, 并重写父类的方 法的方式 来实现多态的效果.
但是在 JavaScript 中本身就支持动态类型, 程序猿在使用对象的某个方法的时候本身也不需要对对象的 类型做出明确区分. 因此并不需要在语法层面上支持多态.
例如:
在 Java 中已经学过 ArrayList 和 LinkedList. 为了让程序猿使用方便, 往往写作
List<String> list = new ArrayList<>()
然后我们可以写一个方法
javascriptvoid add(List<String> list, String s) { list.add(s); }我们不必关注 list 是 ArrayList 还是 LinkedList, 只要是 List 就行. 因为 List 内部带有 add 方法.
当我们使用 JavaScript 的代码的时候
javascriptfunction add(list, s) { list.add(s) }add 对于 list 这个参数的类型本身就没有任何限制. 只需要 list 这个对象有 add 方法即可. 就不必像 Java 那样先继承再重写绕一个圈子
class&构造方法
在 ES6 之前是没有 class 的,没有类
但是 ES6 中就引入了 class,我们通过一个 class 就可以把对象构造出来了
代码展示👇
javascriptclass People{ //构造方法 constructor(name,height,weight){ this.name=name; this.height=height; this.weight=weight; } Say(){ console.log(this.name + "正在说:Hello") } } let CoderYanger = new People("CoderYanger",180,120) console.log(CoderYanger) CoderYanger.Say()效果展示👇
static 关键字
在 Java 中,有些变量是属于 class 的,但不属于对象,此时怎么操作呢?定义 static 变量
代码展示👇
javascriptclass People{ //构造方法 constructor(name,height,weight){ this.name=name; this.height=height; this.weight=weight; } Say(){ console.log(this.name + "正在说:Hello") } static other="other" } let CoderYanger = new People("CoderYanger",180,120) console.log(CoderYanger) CoderYanger.Say() alert(People.other)效果展示👇
再定义一个静态方法,代码展示👇
javascriptclass People{ //构造方法 constructor(name,height,weight){ this.name=name; this.height=height; this.weight=weight; } Say(){ console.log(this.name + "正在说:Hello") } static Sum(){ return 100 } } let CoderYanger = new People("CoderYanger",180,120) console.log(CoderYanger) CoderYanger.Say() alert(People.Sum())效果展示👇
注意,这个方法是属于 class 的,而不属于对象,代码展示👇
javascriptCoderYanger.Sum()此时就会报错,效果展示👇
继承(了解)
ES6 引入了 class 后,不但实现了构造方法,还实现了继承
代码展示👇
javascriptclass People{ //构造方法 constructor(name,height,weight){ this.name=name; this.height=height; this.weight=weight; } Say(){ console.log(this.name + "正在说:Hello") } static Sum(){ return 100 } } let CoderYanger = new People("CoderYanger",180,120) console.log(CoderYanger) CoderYanger.Say() // CoderYanger.Sum() alert(People.other) alert(People.Sum()) class Student extends People{ constructor(name,height,weight,number){ super(name,height,weight) this.number = number } Say(){ alert(this.name) } } let student = new Student("小CoderYanger",180,120,1) console.log(student) student.Say()效果展示👇


































