class背后的原理
使用 class 的语法,让开发者告别了使用 prototype 模仿面向对象的时代。但是,class 并不是 ES6 引入的全新概念,它的原理依旧是原型继承。
JS开发者传统的常用做法是用构造函数来模拟类的实现,通过将属性和方法定义在原型上将自身的属性共享给它的实例。
typeof class == “function”
- 当我们使用 class 定义属性(方法)的时候,实际上等于是在 class 的原型对象上定义属性。
class Foo {
constructor(){ /* constructor */ }
describe(){ /* describe */ }
}
// 等价于
function Foo (){
/* constructor */
}
Foo.prototype.describe = function(){ /* describe */ }
- constructor 是一个比较特殊的属性,它指向构造函数(类)本身。可以通过以下代码验证。
Foo.prototype.constructor === Foo // true
ES6 也提供了类继承的语法 extends
class其实跟构造函数的实现没有什么本质的差别,类本身也是一个函数,类的所有方法也是定义在prototype上,类本身指向它的构造函数,class的实现还是基于prototype的,它只是把prototype藏起来了。
不少人管这种写法叫做ES6的语法糖
- ES6的class中只有实例属性,无法定义类成员属性,只能定义方法。
在ES6中,类的实例属性只能定义在构造函数中,用this关键字定义只属于实例对象本身的属性,实例之间互不影响
而在class中,如果我们想定义一个实例之间共享的属性,那就只能用搬出我们的.prototype把属性定义到类的原型对象上
- 在这一段代码中,Corgi类继承了Dog类,它能够改写实例属性还能调用父类的方法。
需要注意的是,子类的构造函数中,用了super方法调用父类的构造函数并继承this对象,再在自己的构造函数中对this对象增加属性和方法。子类不能自己生成this,而super最关键的作用就是生成this对象。
class Corgi extends Dog{
constructor(name,age){
super(name);
this.name = 'Tom';
this.age = age;
}
}
var corgi = new Corgi('corgi',2);
corgi.name //Tom
corgi.age // 2,不调super()则会因为找不到this对象无法初始化age的值
corgi.saySomething() //汪汪汪
JS没有重载
关于apply和call,bind
typeof Date(2019,2,9); //"string"
typeof new Date(2019,2,9); //"object"
-
通过apply、call调用的都是作为普通函数来调用的
-
bind会生成一个新函数,可以当作构造函数,而apply只是普通的函数调用,bind和apply最大的区别就在于构造函数和普通函数,构造函数返回的是对象
bind 是返回对应函数,便于稍后调用;apply 、call 则是立即调用 。
Object.prototype.toString.call(obj)这个是用来判断obj数据类型,
如果obj是数字,得出的结果是[object Number],从零开始数,第8位就是N,最后一位的前一位就是r,所以取得Number;
如果obj是字符串,得出结果是[object String],第8位S,最后一位的前一位g,取得String
所以,function type(obj){
return Object.prototype.toString.call(obj).slice(8,-1);
}
是用来判断obj的类型是"String" 还是 “Object” 还是 "Number"等等