JavaScript基础(二)
一. 流程控制语句
1)条件控制
- if
if(条件表达式) ...//执行语句
if(条件表达式) {
...//执行代码块
}
- if…else…
if(条件表达式) {
...//执行代码块
} else {
...//执行代码块
}
- if…else if…else
if(条件表达式) {
...//执行代码块
} else if(条件表达式) {
...//执行代码块
} else {
...//执行代码块
}
- switch
switch(条件表达式) {
case 表达式1:
...//执行语句
break;
case 表达式2:
...//执行语句
break;
...
default:
...//执行语句
break;
}
2)循环
- for
循环代码块一定的次数 - for/in
循环遍历对象属性
for(key in Object) {}
- while
当条件为true时循环代码块 - do…while
使用情况和上边一样,当条件为true时循环指定代码块
do{
//TODO
} while(condition)
- continue 和 break
break:跳出循环,继续执行循环之后的代码(如果有的话)
continue:跳出当前迭代,继续执行该循环的下一迭代
二. JavaScript对象
1)什么是对象?
在JavaScript中,一切皆对象,包括String、Boolean、Number、Function、Date、Array、Math、Error、RegExp、Object、Global、Window以及用户自定义对象。一个对象也是一个变量,它拥有自己的属性和方法,或者说它是一个可以包含多个其他变量的容器,这些变量以键值对的形式存在于对象内部。
2)对象的创建
- 手动写出对象的内容,所创建的对象又被称为 对象字面量,如下所示:
let person = {
name: 'Mary',
age: 20,
greet: function() {
alert('Hi! I am '+this.name)
}
- 通过类实例化一个对象
funtion Person(name, age) {
this.name = name
this.age = age
this.greet = function() {
alert('Hi! I am '+this.name)
}
}
let person1 = new Person('Mary', 20)
js中本身没有class的概念,所以其实是通过构造函数的方式来实现。
- create() 额外的一个,就不单独拿出来写了
//接着上边的示例
let person2 = Object.create(person1)
create() 实际做的是从指定原型对象创建一个新的对象,比如例子中就是以person1为原型对象创建了person2。
补充:指定原型对象有时候很有用,我们可以不用再定义构造函数,也可以创建出一个不继承任何原型的绝对干净的对象。
3)访问与设置对象属性
- 点表示法
接着上面创建的对象示例:
person.name //获取name属性值
person.greet //获取greet方法的定义
person.greet() //执行greet方法并获取结果
person.name = { //重新设置name属性值
first: 'Mary',
last: 'Smith'
}
person.name.first //子命名空间链式访问
person.phone = '13133802263' //设置一个新的属性
注意函数的不同访问方式以及对象中函数的调用!
对象的属性仍然可以是一个对象,比如重新设置的name属性,这实际上创建了一个子命名空间,子命名空间中的属性直接链式使用点表示法就可以访问了。
- 括号表示法
person['name'] //获取name属性值, = person.name
person['name']['last'] //获取name中的last属性的值, =person.name.last
let foo = 'age'
person[foo] = 22
根据以上示例可以知道,括号表示法一个非常有用的地方就是,它不仅可以动态的去设置对象成员的值,还可以动态的去设置成员的名字,即括号中可以使用存储有属性名称的变量。
4)对象原型
JavaScript是一种基于原型的语言,每个对象都有一个原型对象,从中继承属性和方法,这个原型对象也可以拥有它自己的原型对象,以此类推,这种关系又被称为原型链。话不多说,上例子~
示例一:
//第一种
var foo = function() {}
console.log(foo.prototype)
//第二种
function foo() {}
console.log(foo.prototype)
//两次打印结果相同,都是默认的原型属性
每个新定义的函数都有一个默认的原型属性,与函数的定义方式无关。
示例二:
//构造函数上的原型属性
function foo() {}
console.log(foo.prototype)
//实例上的原型属性
let instance = new foo()
console.log(instance.__proto__)
//or console.log(Object.getPrototypeOf(instance))
每个实例上都有一个原型属性,实例上的原型属性和构造函数上的原型属性指向的是同一个对象,注意两者的访问区别。
示例三:
//接示例二
foo.prototype.attr1 = 'abcde'
console.log(instance.__proto__.attr1)// result1: abcde
console.log(instance.attr1) // result2: abcde
instance.__proto__.attr2 = 'aaa'
console.log(foo.prototype.attr2) // result3: aaa
console.log(foo.attr2) // result4: undefined
console.log(instance.attr2) // result5: aaa
instance.attr3 = 'bbb'
console.log(instance.__proto__.attr3)// result6: undefined
console.log(foo.prototype.attr3) // result7: undefined
console.log(foo.attr3) // result8: undefined
通过result2、result5可以发现,定义在原型对象上的属性也可以通过实例直接访问到,但是!!!并不是实例对象将原型对象中的属性复制了一份,而是通过原型链的方式访问到的,访问顺序如下:
1.先查找实例对象instance中有无目标属性;
2.没有的话,继续在实例的原型属性__proto__中查找有无目标属性;
3.没有的话,继续在__proto__属性的原型属性中查找……
最后,当所有的原型属性都被查找完了也没找到的话,该属性就是undefined;找到的话,返回找到的值。
三. js中的经典OOP特性:类
1)实现
class Person {
name; //可以直接省略这一步声明,也可以给一个值 name='';
constructor(name) {
this.name = name //如果没有声明的话,会先创建一个name属性
}
greet() {
console.log('This is' + this.name)
}
}
用class关键字声明类,constructor关键字声明构造函数。构造函数的执行过程如下:
1.先创建一个对象
2.将this绑定到所创建的对象,可以在构造函数以及之后的方法中通过this引用该对象
3.执行构造函数中的代码
4.返回这个对象
当然,如果没有需要特殊初始化的东西,也可以省略构造函数,那么通过类进行实例化的时候就会调用默认的构造函数,生成一个只有原型属性的对象。
2)继承
class Employee extends Person{
job;
constructor(name, job){
super(name)
this.job = job
}
greet(){ //重写
console.log('This is'+this.name+', my job is'+this.job)
}
}
用extends关键字继承类,在构造函数中初始化自己的新属性之前,需要先通过super()调用父类的构造函数;父类中的方法也会被继承过来,但是可以重写。
3)封装
class Employee extends Person{
#age; //私有属性
constructor(name, age){
super(name)
this.#age = age
}
#showAge() { //私有方法
console.log('I\'m '+this.#age+' years old.')
}
greet() {
console.log('This is '+this.name)
this.#showAge()
}
}
let employee = new Employee('Jack', 20)
employee.greet()
//This is Jack
//I'm 20 years old.
employee.showAge()
//Uncaught TypeError: employee.showAge is not a function
封装一个很重要的点就是不能由外部任意改变内部数据嘛(我理解的),所以这块涉及到一个私有数据属性,通过以上示例代码可以看到,私有属性由#标记,可以在内部访问,但是在外部访问的时候就会报错。