最近学习了JavaScript,刚学完函数,学后面期约的时候又看到了静态函数的概念,发现自己对前面的知识有些遗忘了,做一个简单的复习总结。初学者有许多不足,请多指教。
静态方法和实例方法的概念
最明显的区别是,静态方法可以用类名.方法名,函数名.方法名调用,实例方法,顾名思义,先new一个实例,用实例名.方法名调用。
开始创建
一、构造函数
1、this出来的方法
先要有构造函数,才会有实例。
function Dog(name,color,age){
this.name=name;
this.color=color;
this.age=age;
this.bark=function(){
console.log('WangWang');
}
}
let dog1= new Dog('Wangcai','red',2);
dog1.bark();
Dog.bark();
很明显,在构造函数内部this出来的方法属于实例函数,用实例dog1调用。
2、函数写在外部
其实本质也是用this
function Dog(name,color,age){
this.name=name;
this.color=color;
this.age=age;
this.bark=bark;
}
function bark(){
console.log('Wangwang');
}
let dog1= new Dog('Wangcai','red',2);
dog1.bark();
Dog.bark();
和刚才是一样的结果
3、在原型上定义的方法
function Dog(name,color,age){
Dog.prototype.name=name;
Dog.prototype.color=color;
Dog.prototype.age=age;
Dog.prototype.bark=function(){
console.log('Wangwang');
};
}
let dog1= new Dog('Wangcai','red',2);
dog1.bark();
Dog.bark();
一样的结果,不放图了,都是实例方法
4、在构造函数内部,用函数名.方法名定义
把上面的代码稍微改了一下
function Dog(name,color,age){
Dog.prototype.name=name;
Dog.prototype.color=color;
Dog.prototype.age=age;
Dog.bark=function(){
console.log('Wangwang');
};
}
let dog1= new Dog('Wangcai','red',2);
Dog.bark();
dog1.bark();
可以看出,这次是dog1.bark没有定义了,但是静态方法调用成功了。
5.在外面添加属性和方法
function Dog(name,color,age){
this.name=name;
this.color=color;
this.age=age;
}
let dog1= new Dog('Wangcai','red',2);
Dog.bark=function(){console.log('Dog bark');};
dog1.bark=function(){console.log('dog1 bar');};
Dog.bark();
dog1.bark();
运行结果
都成功了,所以在函数外也可以用函数名.方法名创建静态函数,用实例化对象名.方法名可以创建实例方法。
在刚才代码的基础上,又实例化了一个新的对象dog2,但是dog2不能调用dog1的方法,在外面额外添加的属性和方法,只属于这个实例。
let dog2= new Dog();
dog2.bark();
这个理由在书本原型链那里讲得比较清楚。
构造函数->函数原型->多个实例
大概是这样一个箭头,实例可以访问原型上的属性和方法,但实例之间是不互通的。
既然提到了函数原型,那就试试在函数外用原型添加方法吧。
function Dog(name,color,age){
this.name=name;
this.color=color;
this.age=age;
}
let dog1= new Dog('Wangcai','red',2);
Dog.prototype.bark=function(){
console.log('Wang');
};
dog1.bark();
let dog2= new Dog();
dog2.bark();
Dog.bark();
其实这和在函数内部是一样的结果,定义在原型上的方法是实例方法。这个定义在函数原型上的方法和刚才的方法不同,可以被所有实例化对象共享。
二、类
类是ECMAScript6新引入的概念。表面上看起来可以支持正式的面向对象编程,实际上使用的仍然是原型和构造函数的概念。
1、类
class Person{
constructor(name,age){
this.name=name;
this.age=age;
this.sayName=function(){console.log(this.name);};
}
sayHello(){console.log(`Hello world`);}
}
let person1 = new Person('Foo',39);
person1.sayName();
person1.sayHello();
运行结果
类本质是一种函数,所以各方面和函数是很像的。
在constructor里,和类块中这样定义的都是普通的实例方法。
这里书上提到,在类块中定义的所有内容都会定义在类的原型上。
person1.sayHello();
Person.prototype.sayHello();
这样是同样的结果,我对代码稍作修改
class Person{
constructor(name,age){
this.name=name;
this.age=age;
this.sayName=function(){console.log(this.name);};
}
sayHello(){console.log(`Hello world,${this.name}`);}
}
let person1 = new Person('Foo',39);
person1.sayName();
person1.sayHello();
Person.prototype.sayHello();
运行结果如下
person1实例上的信息,name并没有存储在原型上。
书上是这么说的,类的静态方法定义在类本身上,并且有Static关键字。所以上面的都是实例方法。
检测一下,直接类名+方法名,报错了
Person.sayHello()
2、类静态方法
class Person{
constructor(name,age){
this.name=name;
this.age=age;
this.sayName=function(){console.log(this.name);};
}
sayHello(){console.log(`Hello world,${this.name}`);}
static sayHello(){console.log('World Hello')}
//static 表示这是一个静态方法
}
let person1 = new Person('Foo',39);
person1.sayName();
person1.sayHello();
Person.prototype.sayHello();
Person.sayHello();
3、其他
在外部添加方法,和函数部分类似。就不一一验证了
person1.sayAge=function(){console.log(this.age);};
person1.sayAge();
Person.sayBye=function(){console.log('Bye');};
Person.sayBye();