原型与新版的类-class
首先来理解原型
原型 === 共用属性
可以先看看方姐的几篇文章:
什么是JS原型链
JS 中 proto 和 prototype 存在的意义是什么?
JS 的 new 到底是干什么的?
var obj = {}
obj.toString = ??? // 按常规逻辑来看,应该是undefined
//然而 打印结果是 "[object Object]"
//所以
obj.toString() = window.Object.prototype.toString()
这样,就做到了代码复用
再来看一个问题
var arr = [1,2,3]
arr.toString() = "1,2,3"
如果说每次调用toString()
都相当于是调用window.Object.prototype
那为什么不同的对象调用同一个toString()
的时候打印出来的值不一样呢?
是不是可以这样假设:toString()
知道是谁调用了它
实际上
obj.toString = obj.toString.call(obj);
obj被传给toString()了
可以来证明一下
var arr = [1,2,3]
var arr2 = [4,5,6]
arr2.toString()
//打印出 "1,2,3" 这没有问题
//那么
arr2.toString.call(arr)
"1,2,3"
//这样就很明显了
原型的用法?

按照上面的逻辑
obj.hi() === 共用属性.hi.call(obj)
那么来改写一下代码
var 共用属性 = {
hi(a){
console.log(a)
}
};
var obj = { name : "我是obj"};
obj.__proto__ = 共用属性
obj.hi() // === 共用属性.hi.call(obj)
能否打印出{ name : "我是obj"}?
结果却是 undefined
???? 什么鬼????
这就要说到js的一个坑了,实际上obj
确实传给了共用属性
,但是 用别的形参无法获取到,只能用this
相当于:
var 共用属性 = {
hi(this,a){
console.log(a)
}
};
这里obj实际上是传给了this,但是js默认隐藏了
所以把代码改成:
var 共用属性 = {
hi(){
console.log(this)
}
};
obj.hi();
{name : "我是obj"}
好,到这我们再来深入探究一下
obj.__proto__
已经等于了共用属性
,也就是说
obj.__proto__ != window.Object.prototype
,那么obj.toString()
会是undefined
吗?
答案是 no。
实际上,当你调用obj.toString()
的时候,首先会在自身上看有没有这个属性,如果没有,就会去你的原型上找,前面已经设置了obj
的原型等于共用属性
,所以,接着会在共用属性
上找有没有toSring
,还是没有,然后会继续去共用属性
的原型window.Object.prototype
上找,找到了之后,调用window.Object.prototype.toString.call(obj)
当然,如果在window.Object.prototype
上也没有找到,会接着去它的原型上找....直到找到或者找到null
为止
可以打印出来看看
window.Object.prototype.__proto__
null
所以,每当你声明一个对象的时候,JS会默认给你执行
新声明的对象.__proto__=window.Object.prototype
或者
新声明的对象.__proto__=window.Array.prototype
什么是类?
var obj1 = {
name : '张三',
age : 18
};
var obj2 = {
name : '李四',
age : 20
};
很明显 obj1
和obj2
很相似,可以把它们归为一类,所以可以把 obj1
和obj2
叫做同一类对象
那如果有不同的对象呢?
var obj3 = {
aaa = 1,
bbb = 2
};
明显跟上面的不能算一类
如果同一类对象分为一类,那么我们怎么用代码表示它呢?
方法有两种:
- 写一个文档,在文档中写清楚
- 提供一个函数来创建这一类的对象
例
function createPerson(name='',age=18){
var obj = {}
obj.name = name
obj.age = age
return obj
};
//开始创建对象
createPerson()
{name : "",age:18}
createPerson("王二狗",16)
{name : "王二狗",age:16}
类是拥有共同特征的对象
再看上面的代码,每个对象的name、age都不一样,怎么在创建它们的时候给它们添加共有属性呢?
当然是用原型
所以代码可以改成
var 共有属性 = {
attr1(){console.log("我们是同类")},
attr2: '同一类'
}
function createPerson(name='',age=18){
var obj = {}
obj.name = name
obj.age = age
obj.__proto__ = 共有属性
return obj
};
开始创建对象

构造函数:创建某个类的对象的函数
类是拥有相同属性的对象
自有属性:对象自身的属性
共有属性:对象原型里的属性
class
每一个class都有一个constructor(构造函数)
,用来构造自有属性

那么共有属性放在哪里呢?
很简单,放在
constructor
外面就可以了
目前 共有属性只能是函数
再来看看复杂一点的
extends
继承

注意:在要继承的对象的构造函数里一定要执行super()
所以继承extends
的意思是:
如果一个类继承了另一个类,那么这个类的对象就有被继承的类的属性
那么super()
的作用是什么呢?
还是看代码

p1
居然具有了Animal的constructor里的属性
所以
super()
的作用就是:执行你继承的类的constructor
被继承的类可以叫做 基类 或者 超类
所以
super()
执行一下超类的构造函数super()
必须放在constructor
的第一行
再来看看 get
我们知道想要调用一个对象里的某个函数,就得用对象名.函数名称()这种方式,
如果在函数前面加一个get
,就可以直接用对象名.函数的方法来调用了

但是有一个很严重的问题,如果前面写错了,后期除了更改源代码以外,没有办法再修改
get
函数里面的内容
所以js又给了我们一个方法, set
具体用法如下

实际上
class
是有些麻烦的 没有原型灵活但是还是有一些优点的,比如某个对象的一个属性,我们想让它是只读的,不允许修改,就可以这样

然后用
set
来控制写入
静态方法 static
静态方法就是只能通过类名.方法名来访问的方法,new出来的对象都不能访问
