原型和原型链
1.1 原型
JavaScript 中,万物皆对象!但对象也是有区别的。分为普通对象和函数对象。
首先看几个非常简单的例子:
console.log(Object.prototype); //Object{}
var o = new Object();
console.log(o.prototype); //undefined
console.log(Array.prototype); //[Symbol(Symbol.unscopables): Object]
console.log(Function.prototype); //function(){}
function hello(){
console.log("hello");
}
hello.prototype = "hello world";
console.log(hello.prototype); //hello world
Object:Object是一个函数对象,Object的原型就是一个Object对象,它里面存在着一些对象的方法和属性,例如最常见的toString方法。
新建对象:用new Object或者{}创建的对象是普通对象,它没有prototype属性,只有__proto__属性,它指向Object.prototype。
Array:Array也是一个函数对象,它的原型就是Array.prototype,它里面存在着一些数组的方法和属性,例如常见的push,pop等方法。
Function:Function也是一个函数对象,但它有点特殊,它的原型就是一个function空函数。
自定义函数:它的原型就是你给它指定的那个东西。如果你不指定,那它的原型就是一个Object.prototype。
1.2 __proto__
这是每个对象(除null外)都会有的属性,叫做__proto__,这个属性会指向该对象的原型。
1.3 constructor
每个原型都有一个constructor属性,指向该关联的构造函数。
1.4 实例与原型
当读取实例的属性时,如果找不到,就会查找与对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层为止。
1.5 原型的原型
原型也是一个对象,既然是对象,我们就可以用最原始的方式创建它
var obj = new Object();
obj.type = 'dog'
console.log(obj. type) // dog
其实原型对象就是通过 Object 构造函数生成的,我们前面讲了,实例的 __proto__ 指向构造函数的 prototype
1.6 原型链
在 javaScript 中,每个对象都有一个指向它的原型(prototype)对象的内部链接。这个原型对象又有自己的原型,直到某个对象的原型为 null 为止(也就是不再有原指向),组成这条链的最后一环。这种一级一级的链结构就称为原型链(prototype chain)。
1.7 最后
大家可以尝试一下以下的代码,看看会得到的答案是什么?先思考再验证哦~
var arr1 = [1,2,3];
console.log(arr1.__proto__);
console.log(arr1.__proto__.constructor);
console.log(arr1.__proto__.__proto__);
console.log(arr1.__proto__.__proto__.constructor);
console.log(arr1.__proto__.__proto__.__proto__);
Class
在 ES6 规范中,引入了 class 的概念。使得 我们前端开发者终于告别了直接使用原型对象模仿面向对象中的类和类继承时代。
2.1 class类概念与语法
基本语法:
class Cat{
static type = 'animal'
constructor(name,age){
this.name = name;
this.age = age;
}
Say(){
return '我的名字是' + this.name;
}
}
var cat1 = new Cat('有鱼',2);
console.log(cat1.Say());
console.log(Cat.type);
-
constructor是一个构造函数方法,创建对象时自动调用该方法
-
constructor是默认存在的,可以省略,程序亦可以调用
-
静态方法:static
-
公有字段
-
私有字段
-
。。。
具体类的基本概念可以参考MDN的详细文档
2.2 class类的继承
通过extends关键字实现类的继承
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
getName(){
return this.name;
}
getAge(){
return this.age;
}
}
class Student extends Person{
getName(){
return '我覆盖了父级的方法,'+ this.name;
}
getScore(){
return '我是子级新增的方法,'+this.name;
}
}
var stu1 = new Student('有鱼',2);
console.log(sut1.getName());// 我覆盖了父级的方法,有鱼
console.log(sut1.getAge());//2
console.log(sut1.getScore());// 我是子级新增的方法,有鱼
通过super关键字进行拓展父类构造器或方法
-
子类使用构造器constructor的时候,必须使用super关键字,用来扩展构造器
-
子类同名方法会覆盖父类同名方法,使用super关键字后则可以调用到父类的同名函数]
2.3 class 实例化的背后原理
JS 中并没有一个真正的 class 原始类型, class 仅仅只是对原型对象运用语法糖,它的原理依旧是原型继承。
class Cat{
static type = 'animal'
constructor(name){
this.name = name;
}
Say(){
return '我的名字是' + this.name;
}
}
var cat1 = new Cat('ivan');
// Cat.prototype
// cat1.__proto__
// cat1.__proto__ === Cat.prototype
说在最后
3.1 TS
3.2 继承
关于继承和设计模式