zoukankan      html  css  js  c++  java
  • 《javascript设计模式与开发实践》阅读笔记(1)—— 多态和原型

    动态类型语言和静态类型语言的区别

    根据数据类型的区别划分,静态语言在编译时已经确定变量的类型,动态语言在程序运行时,变量被赋予某个值之后,才具有某种类型。

    静态语言在实际开发中为什么比动态语言繁琐

    静态语言在编译时要进行类型检测,也就是说函数之类只能定好接收什么类型的变量。为了实现多态,可能的取值须放在一个类里面,函数接受这个类,而具体的变量则继承这个类的类型。
    动态语言则不需要这么繁琐,因为他没有严格的类型检测,不过这样也会带来一些莫名其妙的问题。各有优缺点。

    何为多态

    接收不同参数,执行结果不一样
    即把“做什么”和“谁去做”分离开来,也可以理解为“做什么”和“怎么去做”是分开的。

    多态的作用

    消化掉过程化的条件分支语句,不用通过if语句检测类型,直接调用行为即可。

    封装

    狭义上是隐藏变量,让外部无法访问;广义上是隐藏所有实现细节,只提供输入和输出的接口。
    变化的需要封装起来,剩下的就是可复用的。

    原型继承

    实质是克隆另一个对象,而不是实例化一个类(类继承)。

    原型链

    找到一个对象作为原型,并克隆它,没有的方法和变量,会向上查找,委托自己的原型。

    Object.getPrototypeOf

    Object.getPrototypeOf(obj)可以获得obj的原型,和obj.__proto__ 完全等价

    1 console.log(Object.getPrototypeOf(obj)===obj.__proto__)// true

    JS的原型继承

    创建的对象是克隆Object.prototype实现的,也就是说,克隆的是某个对象的原型,而不是这个对象本身。
    但考虑一下内存分配会发现,新对象并没有占去和原型一样的内存,也就是说,这里的克隆实质更类似于引用,需要调用这种方法时就会到祖先这里调用。所以为了提高性能,减少内存的浪费,添加公用方法时,多数添加到原型(prototype)上,这样可以被别的对象很好的继承。

    prototype和__proto__

    JS 是基于原型继承,也就是说真正继承的东西都在prototype里,如果obj是个对象,那obj.prototype也是个对象,我们继承或者说克隆的就是这个对象的属性和方法,这里我们把它叫做原型对象。

    而__proto__是所有对象都具有的属性,指向其构造器的原型对象,也就是指向构造器的prototype;或者换个好理解的方式就是指向继承的对象,也就是说,__proto__指向的就是自己克隆的对象,是自己的原型,这里我们把__proto__称为原型或者是原型指针。

    核心的一句话,所有对象的__proto__都指向其构造器的prototype,即所有对象的原型就是其构造函数的原型对象。

    例子:

    function Person(){};
    var p=new Person();
    console.log(p.prototype);
    //undefined 构造函数才有原型对象(prototype),普通对象寻找原型应该用__proto__ console.log(p.__proto__===Person.prototype); //true p(对象)的原型(__proto__)就是Person(构造函数)的原型对象(prototype)

    对象有一个属性 constructor,可以返回它的构造函数

    console.log(p.constructor===Person)  //true   
    
    console.log(Person.prototype.constructor===Person) //true   原型对象也是对象,也能指向自己的构造函数

    所以下面的都成立

    console.log(Person.prototype.constructor===p.constructor) //true
    
    console.log(p.__proto__.constructor===Person.prototype.constructor); //true
    console.log(p.constructor===p.__proto__.constructor) //true 自己和原型的构造函数是同一个

    所以说白了,继承的东西就是原型对象,__proto__就是指向继承的原型对象

    那么问题一:对象的原型对象有原型对象么?

    console.log(Person.prototype.prototype)  //undefined

    结论:构造函数才有原型对象,然后没了,原型对象是没有原型对象的。

    问题二:原型对象也是对象,那它有原型么?

    console.log(Person.prototype.__proto__===Object.prototype)  //true

    结论:有的,原型对象的原型(.__proto__)还是一个原型对象

    问题三:所有对象的原型是什么?

    var a={};
    
    console.log(a.__proto__===Object.prototype)   //true   对象的原型是 Object.prototype
    console.log(Object.prototype.__proto__);   //null

    结论:Object.prototype处于原型链的最上端,包含很多方法,属性,可以理解为所有对象的原型,而它的原型为null,即空,不存在。

    比较有意思的是Object这个构造器,它既是构造器也是对象,是对象就有原型

    console.log(Object.__proto__===Function.prototype);  //true    Object的原型Function的原型对象
    
    console.log(Object.prototype===Function.prototype.__proto__); // true 而Object的原型对象是Function原型对象的原型,这里有点绕,换下面这种写法
    console.log(Object.prototype===Object.__proto__.__proto__); //true 可以看到Object的原型对象是它原型的原型

    我们说过,原型意味着克隆继承,也就是说Object绕了一圈继承了自己的原型对象,原型链应该是条链子,__proto__连接继承的对象,prototype给别人继承,而Object这里打了个结,这种特殊性说明了它的特殊地位,而实现“打结”的关键则是Function对象,再看一个可能会更清楚

    console.log(Function.constructor===Function)  //true 
    
    console.log(Function.__proto__===Function.prototype) //true

    一切就源于这里,Function自己是自己的构造器,所以__proto__(原型)就指向自己的prototype(原型对象)

    Function同时也是Object 的构造器

    console.log(Object.constructor===Function) //true

    所以Object的__proto__指向Function的prototype,那么整理一下就是这样的

    Object,

    Object.__proto__ /Function.__proto__ =>Function.prototype,

    Function.prototype.__proto__ => Object.prototype,

    Object.prototype.__proto__ => null

    原型模式

    通过克隆来继承的设计模式

  • 相关阅读:
    第6课:datetime模块、操作数据库、__name__、redis、mock接口
    第5课:内置函数、处理json、常用模块
    第4课:函数、模块、集合
    第3课:列表和字典的增删改查、字符串常用方法、文件操作
    第2课:jmeter总结、Charles抓包
    第1课:接口测试和jmeter总结
    Centos下找不到eth0设备的解决方法
    Python安装、配置
    改进的SMO算法
    拉普拉斯特征图降维及其python实现
  • 原文地址:https://www.cnblogs.com/grey-zhou/p/5913690.html
Copyright © 2011-2022 走看看