原型与新版的类-class

2018-12-30  本文已影响0人  我也不知道啊丶

首先来理解原型
原型 === 共用属性
可以先看看方姐的几篇文章:
什么是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
};

很明显 obj1obj2很相似,可以把它们归为一,所以可以把 obj1obj2叫做同一类对象
那如果有不同的对象呢?

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是有些麻烦的 没有原型灵活
但是还是有一些优点的,比如某个对象的一个属性,我们想让它是只读的,不允许修改,就可以这样
用this._隐藏属性,然后在get中return出去,没有set就无法修改
然后用set来控制写入
在set里设置规则来控制写入

静态方法 static
静态方法就是只能通过类名.方法名来访问的方法,new出来的对象都不能访问

上一篇 下一篇

猜你喜欢

热点阅读