你不知道的javascript之 Object.create 和 new 区别

来源:互联网 发布:现在淘宝开店多少钱 编辑:程序博客网 时间:2024/06/07 06:41

博客原文地址:http://blog.csdn.net/blueblueskyhua/article/details/73135938

前几天有碰到原型的问题。之前以为自己对原型还是有所了解,但是细细研究,发现自己对原型的理解还是太年轻了。

这里写图片描述

Object.create 和new

创建对象的方式,我以我碰到的两种创建方式,Object.create 和new来说明

var Base = function () {}var o1 = new Base();var o2 = Object.create(Base);
  • 1
  • 2
  • 3

那这样到底有什么不一样呢?
这里写图片描述

我先来一段Object.create的实现方式

Object.create =  function (o) {    var F = function () {};    F.prototype = o;    return new F();};
  • 1
  • 2
  • 3
  • 4
  • 5

可以看出来。Object.create是内部定义一个对象,并且让F.prototype对象 赋值为引进的对象/函数 o,并return出一个新的对象。

再看看var o1 = new Base()的时候new做了什么。

JavaScript 实际上执行的是:var o1 = new Object();o1.[[Prototype]] = Base.prototype;Base.call(o1);
  • 1
  • 2
  • 3
  • 4

new做法是新建一个obj对象o1,并且让o1的__proto__指向了Base.prototype对象。并且使用call 进行强转作用环境。从而实现了实例的创建。

我们来看看两个对象打印情况。
这里写图片描述
看似是一样的。

我们对原来的代码进行改进一下。

var Base = function () {    this.a = 2}var o1 = new Base();var o2 = Object.create(Base);console.log(o1.a);console.log(o2.a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

这里写图片描述

可以看到Object.create 失去了原来对象的属性的访问。
那再看看prototype呢?(一开始没理解prototype和__proto__ 的关系。造成对这两种方式的创建理解非常费解)。
再一次对代码进行改进。

var Base = function () {    this.a = 2}Base.prototype.a = 3;var o1 = new Base();var o2 = Object.create(Base);console.log(o1.a);console.log(o2.a);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

我一开始以为输出的值是2,3。。。以为prototype还是存在的。。结果发现真的发错特错。我们看运行的结果。
这里写图片描述
依旧是如此。

这里写图片描述

那我们就以图说话。

这里写图片描述

这里写图片描述
(F在创建后被销毁)

看完上图,我们就知道了,为什么通过Object.create构造的连Base原型上的属性都访问不到,因为他压根就没有指向他的prototype。这也就说明了__proto__prototype 的区别。所以上面在prototype定义的a,只是Base的prototype对象上的一个属性。

再来看看就是:

  1. new关键字必须是以function定义的。
  2. Object.create 则 function和object都可以进行构建。

instanceof 和 isPrototypeOf

写了创建一个对象实例,并且说了通过原型链来完成这一个个对象之间的联系,但是你怎么知道就一定含有呢?所以我们需要一个判断机制。

这里写图片描述

function Foo(){    //...}Foo.prototype.ff = 2;var a  = new Foo();a instanceof Foo; //true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

instanceof 说的是在a的整条[[Prototype]] 是否含有Foo.prototype对象。 但是这个方法只能实现对象(a)和函数(带.prototype引用的Foo),如果你想判断两个对象(a 和 b)是否通过[[Prototype]]链关联。只用instanceof就无法实现。

所以这里用到了isPrototypeOf。

var a = {};var b = Object.ceate(a);
  • 1
  • 2

b.isPrototypeOf(a);//在a的[[Prototype]]是否出现过b来判断。

来看看isPrototypeOf实现方式。

function isRelatedTo(o1,o2){    function F(){}    F.prototype = o2;    return o1 instanceof F;}
  • 1
  • 2
  • 3
  • 4
  • 5

上述函数通过了构建一个辅助函数F,构建了一个prototype对象。从而达到instanceof比较的条件。
console.log(a.isPrototypeOf(b) === isRelatedTo(b,a));// true

constructor

我们先来看看下面的代码。

function Foo(){}console.log(Foo.prototype.constructor === Foo);//truevar a = new Foo();console.log(a.constructor === Foo);//true
  • 1
  • 2
  • 3
  • 4
  • 5

看起来a.constructor === Foo 为真意味着a的确有一个.constructor指向Foo的.constructor属性,但事实并不是这样的。

function Foo(){}Foo.prototype = {}var a1 = new Foo();console.log(a1.constructor === Foo);//falseconsole.log(a1.constructor === Object);//true
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

可以看到a1并没有.constructor属性。那是为什么呢。?因为a1没有.constructor属性,他会委托[[prototype]]链上的Foo.prototype。但是新建的Foo.prototype也没有.constructor,所以继续往上找,一直到了顶端的Object.prototype。
你可以手动地进行修正.constructor的指向。
所以可以看出.constructor是一个非常不可靠,并且不安全的引用。在开发中尽量避免使用这些引用,。

原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 银行卡限额怎么办京东 预留信息忘了怎么办 中信银行香港卡怎么办 无银行预留信息怎么办 农工商超市红利卡怎么办 余额宝转入不了怎么办 公司车辆怎么办营运证 便利店转不出去怎么办 便利店开业营业额低怎么办 现在etc超时了怎么办? 中国银行e贷逾期怎么办 招商银行e分期逾期怎么办 保单贷款还不了怎么办 离婚时按揭房怎么办 按揭房子不要了怎么办? 征信有问题怎么办房贷 夫妻一方不做房贷共还人怎么办 给你花逾期一年怎么办 文件夹密码忘记了怎么办 网址被qq拦截怎么办 手机qq邮箱中毒怎么办 邮箱附件带病毒怎么办? 打开了病毒附件怎么办? qq邮箱被拦截怎么办 邮件地址已被注册怎么办 信用卡欠款怎么办房贷 贷款还不起了怎么办 装修贷款无抵押怎么办 黑户买房做贷款怎么办 易分期无法还款怎么办 工行晚还款一天怎么办 手机银行网页打不开怎么办 顺丰分拣错误怎么办 超市生意越来越差怎么办 收到逾期催收函怎么办 手机贷逾期了怎么办 临额到期还不上怎么办 信用卡不想用了怎么办 授信时间到了怎么办 餐饮吃到苍蝇怎么办 商户二级处罚了怎么办