JS中的对象和__proto__ 、prototype

在Javascript中,万物皆对象,但对象也有区别,大致可以分为两类,即:普通对象 Object 和 函数对象 Function。 一般而言,通过 new Function 产生的对象是函数对象,其他对象都是普通对象。

举例说明:

function f1() {
    // todo
}
var f2 = function () {
    // todo
};
var f3 = new Function('x', 'console.log(x)');

var o1 = {};
var o2 = new Object();
var o3 = new f1();

console.log(
    typeof f1,
    typeof f2,
    typeof f3,
    typeof o1,
    typeof o2,
    typeof o3
);
//输出 > "function" "function" "function" "object" "object" "object"

f1属于函数的声明,最常见的函数定义方式,f2实际上是一个匿名函数,把这个匿名函数赋值给了f2,属于函数表达式,f3不常见,但也是一种函数对象。

Function 是JS自带的对象,f1,f2 在创建的时候,JS会自动通过 new Function() 的方式来构建这些对象,因此,这三个对象都是通过 new Function() 创建的。

Object 和 Function最大的区别是:每个Function对象都有一个prototype表,而 Object没有。

在 Javascript 中创建对象有两种方式:大括号和使用new表达式,o1和o2的创建恰好对应了这两种方式,重点讲一下o3, 如果用Java和C#的思路来理解的话,o3是f1的实例对象,但是o3和f1是不同类型的对象。

为什么呢? 需要理解一下JS的new和构造函数的原理:

 
// ===================new 与构造函数 机制=========================
function person(name, age) {
	this.name = name;
	this.age = age;
}
// 机制1 每一个函数对象都有一个表, prototype;
console.log(person.prototype);
person.prototype.get_age = function() {
	return this.age;
}
// 机制2: new 关键字 + 函数(参数)
// step1: 创建了一个新的表 {};
// step2: 调用person函数,并把这个新的表作为this传递给函数,进入person里面以后;
// person函数里面this 就是新建的表;
// step3: 将person构造函数的prototype这个表赋值给新的表(this)的.__proto__
// step4: 返回这个新的表;
// new 函数(参数) 的作用是构建一张新的表, 这个函数作为构造函数的作用是初始化表对象;
var p = new person("xiaoming", 34);
//上面四个步骤的伪代码表示
 var p = {} //step1
 person.call(p,"xiaoming", 34); //step2
 person.__proto__ = person.prototype //step3
//第四步省略

由上面代码中的注释可以看出,new constructor()返回的是一个Object。Object对象也叫表

当我们用new调用一个函数时,这个函数也就成了构造函数,new 操作符返回的结果叫做实例。

下面我们把new一个函数返回的对象叫做实例。

可以先通过下面代码的打印输出,理解一下__proto__ 与prototype:

function Base(){
    this.baseNum = 1;
    this.fun1= function(){
        console.log("Base.fun1")
    }
  }
  Base.prototype.num = 10
  Base.prototype.fun1 = function(){
    console.log("prototype.fun1")
  }
  let obj = new Base()
  obj.fun1()
  obj.__proto__.fun1()
  console.log("Base.prototype:",Base.prototype)
  console.log("Base.__proto__:",Base.__proto__)
  
  console.log("obj.prototype",obj.prototype)
  console.log("obj.__proto__",obj.__proto__)
  console.log(obj.__proto__ == Base.prototype)//true
  console.log(Base.prototype.__proto__==Object.prototype) //true
  console.log(Object.prototype.__proto__) //null

输出结果:

 由上面代码和输出结果可以得出:

obj中__proto__保存的是 Base的 prototype,Base的 prototype 中的 __proto__保存的是Object的prototype,而Object.prototype.__proto__ 是 null。

prototype:只是定义了实例的数据类型

每一个函数对象都有一个prototype表,但是函数对象不能访问它的prototype,只能定义它的prototype的数据,prototype定义的属性和方法专门留给函数对象的实例访问的:

function f(){}
f.prototype.foo ="abc";
console.log(f.foo);// undefined
var obj =new f();
console.log(obj.foo);// abc
  1.  代码中的f.prototype虽然和obj 都是一个Object,但是他们表示的意义完全不同:prototype是一个类型的定义或类的定义,obj 是类型(或类)的实例。
  2. 类的定义只有一份,类的实例可以有很多个,所有new f()得到的实例,共享同一个prototype,通过实例的__proto__访问。

__proto__:引用函数对象的 prototype 

__proto__: 存在于普通对象和函数对象中它的作用就是引用函数对象的 prototype 对象,JS在通过 new 操作符创建一个对象的时候,通常会把父类的 prototype 赋值给新对象的 __proto__属性。

__proto__原型链搜索:

搜索机制:JS引擎访问obj对象属性时,先查找对象本身是否存在属性,如果不存在,会在obj.__proto__上查找,也就是在f.prototype上查找。

f.prototype也没有的话,会递归调用f.prototype的搜索机制,下面就搜到了Object.prototype,

Object.prototype.__proto__是null,终止了递归搜索。

没有__proto__和prototype 也可以实现继承关系的:

当然ES6之后JS就有了class和extends关键字,不需要这么麻烦:

function Base(){
    this.baseNum = 1;
    this.funBase = function(){
        console.log("funBase")
    }
  }
  function A(){
    Base.call(this)
    this.aNum = 2
    this.funA = function(){
        console.log("funA")
    }
  }
  let a_obj = new A()
  console.log(a_obj.baseNum)
  a_obj.funBase()
  function B(){
    A.call(this)
    this.bNum = 22
    this.funB = function(){
        console.log("funB")
    }  
  }
//A继承了Base,B继承了A和Base
  let b_obj = new B()
  b_obj.funB()
  b_obj.funA()
  b_obj.funBase()

  

输出:

上面代码中的函数B没有定义prototype也实现了继承与A和Base

上面代码的成员函数直接定义在this中,实际编码很少这样写。 我们把函数作为类来定义的时候,成员函数一般都定义在prototype。

例如:我们把TypeScript的类定义代码编译成JS代码:

 

编译好的代码中,类的成员函数定义在 prototype中。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值