传统的javascript中只有对象,没有类的概念。它是基于原型的面向对象语言。原型对象的特点就是将自身的属性共享给新对象。
如果要生成一个对象实例,需要先定义一个构造函数,然后通过new操作符来完成。构造函数示例:
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.say = function () {
return "我的名字叫" + this.name + "今年" + this.age + "岁了";
}
var obj = new Person("Ann", 18); //通过构造函数创建对象,必须使用new运算符
console.log(obj.say());
ES6引入了Class(类)这个概念,通过class关键字来定义类。这样的写法更加清晰,更像是一种面向对象的语言。
类其实就是构造函数的另外一种写法:
class Person { // 定义了一个名字为Person的类
constructor(name, age) { // constructor是一个构造方法,用来接收参数
this.name = name; // this代表的是实例对象
this.age = age;
}
say() { // 这是一个类的方法,在Person原型上,而不是基本属性里,这里要注意千万不要加上function
return "我的名字叫" + this.name + "今年" + this.age + "岁了";
}
}
var obj = new Person("Ann", 18);
console.log(obj.say());
注:(1)在类中声明方法的时候,千万不要给该方法加上function关键字
(2)方法之间不要用逗号分隔,否则会报错
由下面代码可以看出类实质上就是一个函数(function)。类自身指向的就是构造函数。
console.log(typeof Person); // function
console.log(Person === Person.prototype.constructor); // true
构造函数的prototype属性,在ES6的类中依然存在:
Person.prototype.say = function () { // 定义与类中相同名字的方法。成功实现了覆盖!
return "我是来证明的,你叫" + this.name + "今年" + this.age + "岁了";
}
var obj = new Person("Ann", 18);
console.log(obj.say()); //我是来证明的,你叫Ann年18岁了
当然也可以通过prototype属性对类添加方法(可以定义与类中相同名字的方法实现覆盖)
通过new生成对象实例时,自动调用constructor方法:
class Box {
constructor() {
console.log(123); // 当实例化对象时该行代码会执行
}
}
var obj = new Box(); // 124
constructor方法如果没有显式定义,会隐式生成一个constructor方法。所以即使你没有添加构造函数,构造函数也是存在的。constructor方法默认返回实例对象this,但是也可以指定constructor方法返回一个全新的对象,让返回的实例对象不是该类的实例:
class Desk {
constructor() {
this.xixi = "haha";
}
}
class Box {
constructor() {
return new Desk();// 这里没有用this,而是直接返回一个全新的对象
}
}
var obj = new Box();
console.log(obj.xixi); // haha
constructor中定义的属性可以称为实例属性(即定义在this对象上),constructor外的属性都是定义在原型上的,称为原型属性。
hasOwnProperty()函数用于判断属性是否是实例属性。
in操作符:对象能够访问给定属性就返回true(无论该属性存在于实例中还是原型中),格式为 “name” in obj
class Box {
constructor(num1, num2) {
this.num1 = num1;
this.num2 = num2;
}
sum() {
return num1 + num2;
}
}
var box = new Box(12, 88);
console.log(box.hasOwnProperty("num1")); // true
console.log(box.hasOwnProperty("num2")); // true
console.log(box.hasOwnProperty("sum")); // false
console.log("num1" in box); // true
console.log("num2" in box); // true
console.log("sum" in box); // true
console.log("say" in box); // false
类的所有实例共享一个原型对象,它们的原型都是Person.prototype,所以proto属性是相等的,都等于构造函数的prototype:
class Box {
constructor(num1, num2) {
this.num1 = num1;
this.num2 = num2;
}
sum() {
return num1 + num2;
}
}
// box1与box2都是Box的实例。它们的__proto__都指向Box的prototype
var box1 = new Box(12, 88);
var box2 = new Box(40, 60);
console.log(box1.__proto__ === box2.__proto__); // true
注:class不存在变量提升(不会把声明提升到代码头部),所以需要先定义再使用:
// ES5可以先使用再定义,存在变量提升
new A();
function A() {
}
// ES6不能先使用再定义,不存在变量提升 会报错
new B(); // B is not defined
class B {
}