1.1 JavaScript 对象
- 所有事物都是对象:字符串、数值、数组、函数…
- 对象为一组属性或方法的无序集合
- 对象的每个属性或方法都由一个名称来标识,这个名称映射到一个值
1.2 创建 JavaScript 对象
- 创建直接的实例
person=new Object();
person.name="xxh";
person.age=24;
person.job="student";
- 使用对象字面量
let person = {
name: "xxh";
age: 24;
job: "student";
}
- 使用构造函数(函数声明、函数表达式)
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
}
let Person = function(firstname,lastname,age,eyecolor){
this.name = name;
this.age = age;
this.job = job;
}
注:按照惯例,构造函数的首字母都要大写。
1.3 原型
原型可以理解成模板,用来模仿JAVA中的类。
先看下面两个例子:
function Person(name,age,job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
console.log(this.name);
};
}
let person1 = new Person("xxh",24,"student");
let person2 = new Person("whh",24,"student");
console.log(person1.sayName() == person2.sayName());//false
var arr1 = [1, 0, 0, 8, 6];
var arr2 = [1, 0, 0, 8, 6, 1, 1];
//数组求和方法
arr1.getSum = function() {
var sum = 0;
for(var i = 0; i < this.length; i++) {
sum += this[i];
}
return sum;
}
console.log(arr1.getSum()); //输出15
console.log(arr2.getSum());//控制台报错
第一个例子中,虽然实例上的函数同名且作用相同,但却是不同的对象。
第二个例子中,在 arr1 上定义的方法,只属于arr1,不属于arr2,因此如果arr2要求和的话还得在arr2上重新定义求和方法。
问题:有没有什么方法可以只做一件事就能解决相同逻辑的需求?
这个问题可以通过原型来解决。
1.3.1 原型
每个JavaScript对象创建的时候,都会创建一个prototype属性,这个prototype就是我们说的原型,它是一个对象。
这个对象作用类似于JAVA中的类,里面储存可以共享的属性和方法。
let Person = function(){};
Person.prototype.name = "xxh";
Person.prototype.age = 24;
Person.prototype.job = "student";
let person1 = new Person();
let person2 = new Person();
console.log(person1.sayName() == person2.sayName());//true
通过原型定义的属性和方法是由所有实例共享的,因此person1和person2访问的是相同的sayName( )。
1.3.2 原型搜索机制
原型链是原型定义方式的属性查找机制。
在通过对象访问属性时,会按照这个属性的名称开始搜索。搜索开始于对象实例本身。如果在这个实例上发现了给定的名称,则返回该名称对应的值。如果没有找到这个属性,则搜索沿着指针进入原型对象,然后在原型对象上找到属性后,再返回对应的值。
上图为原型图解,对于实例person1而言,当需要访问sayName时,会首先搜索person1实例本身,没有发现则进入prototype对象搜索,得到sayName方法。
1.4 类
在ES6中为了解决原型实现继承的代码过于冗长的问题,正式定义了类。
1.4.1 类定义
- 以表达式定义类
//匿名类
let Example = class {
constructor(a) {
this.a = a;
}
}
//命名类
let Example = class Example {
constructor(a) {
this.a = a;
}
}
- 以声明方式定义类
class Example {
constructor(a) {
this.a = a;
}
}
1.4.2 类方法
-
类构造函数
constructor方法是类的默认方法,创建类的实例化对象时自动被调用,不定义时相当于将构造函数定义为空函数。
class Example {
constructor() {
console.log("前端真好玩!");
}
}
new Example();//前端真好玩!
当使用new创建对象时,构造函数会执行以下操作:
1.在内存中创建对象
2.给这个对象的 prototype 赋值
3.构造函数内部的 this 赋值为这个对象
4.执行构造函数内部的代码(给新对象添加属性)
5.如果指定了返回对象,则返回该对象;否则返回刚创建的新对象
-
原型方法
把在类块中定义的方法定义到原型中,以便在实例间共享。
class Example {
sum(a, b) {
console.log(a + b);
}
}
let exam = new Example();
exam.sum(1, 2);//3
-
静态方法
静态方法通常用于执行不需要实例来完成的操作。静态方法的 this 指向类本身。
class Example {
static sum(a, b) {
console.log(a + b);
}
}
Example.sum(1, 2);//3
1.4.3 继承
通过 extends 实现类的继承。
-
super
用来新建父类的 this 对象。
子类没有自己的 this 对象,如果不调用 super,子类就得不到 this 对象。
class Demo2 extends Demo{
constructor(x,y){
this.x = x; //this is not defined
}
}
调用父类方法,super 在静态方法中指向父类,在普通方法中指向父类的原型对象。