对象、类、原型详解

176 阅读5分钟

对象:

关于null

typeof null == object的原因不止是null指向空对象
原理是不同的对象在在底层都是以二进制表示的,在js中如果前三位都是0那么就会被判断位object类型,null是所有的二进制都是0,因此null是object类型

tips:
对象的属性名都是字符串,如果是其他类型,会调用toString方法
显示的结果就如Object.prototype.toString.call()查看的类型值一致

Array也是对象下的一个子类型,有趣的是,对象可以通过对象.属性来进行赋值或者替换,而同样的数组也具备这个功能

let arr = [1,2,3];
arr.name ="张三"
console.log(arr.name) //"张三"

数据属性以及访问器属性

共有的属性:
value:默认值 writable: 可修改(如果值是false,则属性值如果修改的话会报错)

数据属性:
configurable: 可配置(如果值是fasle的话,Object.defineproperty不可再对同样的对象属性进行修改)
值得注意的是configurable如果是false的话,delete是无法删除这个属性的

enumerable: 可枚举(如果是false的话,for..in循环无法枚举该属性,但是能正常访问)



访问器属性:
set: 赋值时调用的函数 get: 获取值时调用的函数

访问器属性调用方式

对象文字语法

let myobj={
    get a(){
        return 2
    }
}
console.log(myobj.a) //2

显示定义

Object.defineproperty(myobj,"a",{
    get:function(){
        return 2
    }
})
console.log(myobj.a) //2




类:

啥是类啊?

类就是描述一种组织代码的数据结构。一种可以反应部分真实世界关系的建模方法

类的设计模式(类也是一种设计模式)(特点)

封装、多态、继承 大部分的创建型设计模式和部分的结构型、行为设计模式也算(本人发布的第一篇关于设计模式的文章有具体描述)

类的机制

比如说stack类
它有弹出,压入的功能,它显示了栈所需要做的事情,但它并不是栈,它是一个把栈的功能描述出来的一个抽象模型。需要对栈进行操作的是把这个抽象模型给实例化变成具体的对象后才能开始的操作

混入mixin

啥是混入啊?混入就是类似与Object.assign()api类似的功能
它实现一个把含有不同属性的类关联起来的功能

显示混入

实现mixin函数,并且关联对象

function mixin(sourceObj,targetObj){
    for(var item of sourceObj){
        if(!key in targetObj){
            targetObj[item]=sourceObj[item];
        }
    }
    return targetObj
}

隐式混入

通过显示绑定的方法实现

var something = {
    cool:function(){
        ...
    }
}

var anotherthings = {
    cool:function(){
        something.cool.call(this)
    }
}

原型:

[[Get]]解析

代码在访问对象下的属性值时,不仅仅是简单的进行RHS查询.
这是当想要引用对象属性当时候触发当操作。对于默认当[[Get]]操作来说,第一步检查当对象本身是否具有[[Prototype]]属性,如果有就调用它

var obj = {
    a:2
}
console.log(obj.a) //2

obj.a实现了obj的[[Get]]操作,类似于在查询的时候调用了钩子函数get。
对象默认的内置[[Get]]操作首先在对象中查找是否存在名称相同属性,如果找到了就返回这个属性的值,如果没找到就返回undefined

[[Put]]解析

赋值或是创建操作 [[Put]]触发取决于很多因素,最为关键的是对象下是否存在对于的属性
如果存在大致会检查如下内容:

  • 是否访问访问器属性get和set,如果存在set调用set
  • 访问writable
  • 如果都没有,将该值设置为属性值

[[Prototype]]解析

[[Protutype]]是当对象下当属性不存在时访问,它记录上级及以上的原型(原型链)
in操作符会检查属性是否在对象内及其[[Prototype]]中,而hasOwnProperty只会检查属性是否存在对象中,不会检查原型链
[[Prototype]]的最终指向是Object.prototype

属性设置

obj.foo = "bar"

此时执行的情况类似有LHS查询。如果属性不直接存在于对象中,编译器会遍历原型链直到查询到对应属性为止,如果在原型链中也查不到,就会在直接对象下创建该属性并赋值,而LHS是在顶层对象下创建一个全局变量;

属性屏蔽

出现屏蔽的情况是直接对象和原型链中同时存在对应属性,这时候直接对象的值会屏蔽原型链上层的所有对应查询的属性,而且总是会选择原型链最底层的属性

构造函数

function Foo(name){
    this.name = name
}
var a = new Foo();
a.constructor == Foo; //true

我们一般用函数定义的类,其实本质上并不是一个类。
那为什么a.constructor指向Foo呢,这不是矛盾了吗???
实际上是这么一回事:
我们使用new来实例化一个新对象时,把这个函数的调用变成了“构造函数调用”,实际上new会劫持普通函数并用构造对象的形式去调用它。

关于Object.creat();

它创建一个新的对象,并把这个对象关联到传入的参数中。
值得注意的地方是如果参数是null,这个新对象无法进行委托,也没有原型链

 手撕:
 if(!Object.create){
     Object.create = funnction(o){
         function f(){
             F.prototype = 0;
             return new F();
         }
     }
 }

关于instanceof

e.g:
a instanceof b
这个程序的意思是普通对象a的整条原型链中是否有函数b.prototype指向的对象