JavaScript中new的运行机制到底是什么?
第一句:JavaScript
提供的内置函数和对象都是全局作用域的属性。
第二句:JavaScript
中使用new
调用函数返回实例对象,该函数会被称为构造函数,作为构造函数是不是必须具备prototype
属性对象?
我刚学JavaScript
不久,这两句话都是我的观察和猜测,不知是错是对。
我对第一句话的认识:
在浏览器环境中,可以做如下操作,
window.Object // 返回 Object()
window.Proxy // 返回 Proxy()
window.isNaN(NaN) // 返回 true
上面代码中的Object
和Proxy
都是JavaScript
提供的内置函数,都可以通过浏览器全局对象window
进行访问,我的理解是宿主环境(浏览器引擎)是基于JavaScript
语法实现的,那么必然会将JavaScript
提供的内置函数,都容纳进浏览器全局对象window
中,以便访问,与浏览器相对应的Node环境应该也是如此,不知如此理解是对是错?
第一句和第二句并不具有绝对相关性。
我对第二句话的认识:
对于以funcion
声明的函数,都会存在prototype
属性。
当使用new
调用以function
定义的函数时,这个函数会被称为构造函数,会发生下面操作:
- 构造函数运行时引擎会产生一个空对象
{}
。 - 引擎会将构造函数
prototype
的引用作为空对象{}
的原型。 - 引擎会将构造函数中的
this
指向这个新生成的对象。 - 构造函数如果不返回其它对象,最终都会返回这个新对象。
- 最重要的一步,引擎会为这个新对象进行初始化,从而调用构造函数的
prototype
属性中的constructor
。
和function
声明的函数不同的是,JavaScript
定义的函数有着不同之处,比如ES6
新加入的Proxy
,使用new
调用Proxy
会生成实例对象,但是实例对象的原型是Object.prototype
而不是Proxy
的prototype
,并且Proxy.prototype
为undefined
。
Object.getPrototypeOf(Proxy) === Function.prototype // true
const proxy = new Proxy({}, {})
Object.getPrototypeOf(proxy) === Object.prototype // true
Proxy.prototype // undefined
同样是函数,一个是function
声明,一个是JavaScript
内置,都可以使用new
调用并返回实例对象,但是前者的prototype
有值而后者没有赋值,这个区别使我对new
的机制产生了很大的疑惑,难道使用new
调用的构造函数可以不需要prototype
么?没有prototype
的Proxy
是怎么生成实例对象的呢?
有没有大佬可以指点一二!!!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
第一句话理解没有什么问题,在浏览器中就是指
window
,在NodeJS中指global
,都是全局作用域
。第二句话就有偏差了,先给结论,
new
的机制不会特殊,是明确的,一贯的,坚定的。先说
new
做了什么:当代码
new Foo(...)
执行时,会发生以下事情:Foo.prototype
的新对象被创建Foo
,并将this
绑定到步骤【1】中创建的对象new
表达式的结果。如果构造函数没有显式返回一个对象,则使用【1】中的值。重点关注一下【3】,构造函数是可以有返回值的,当返回值为
对象
时,new
的结果是这个对象,而不是【1】创建的对象。这个可以参看类似的问题,我的笔记,MDN->new操作符。
new
的机制,这个对所有函数
都是一样的,不存在特殊。然后再说原型链预期不一致:
这里
new Proxy
,但是原型链却是指向Object.prototype
,原型链不是预期的Proxy.prototype
,这就有多种手段可以做到:比如上面说的
new
操作的【3】里面返回了一个对象
。这个对象
有自己的原型链,跟构造函数就没有关系了。可以这样想象
Proxy
的构造函数:Object.getPrototypeOf
,那么也同样可以使用Object.setPrototypeOf
再说,
Proxy
实现:我们无法看到内置实现,但是我们可以看看其
polyfill
,看看这个是怎么实现的,就能了解其基本原理:GoogleChrome的Proxy polyfill实现看其构造函数,摘抄一部分:
可以看到,其
polyfill
实现确实改变了其原型链
指向,使用了我们上面说的第2
种方式,重点是指向的是target
的原型链。Proxy
既然是代理,那你只能代理我
,而不能改变我
,我
原来是object
,那代理后的我
依然是object
,如果经过代理之后,我
原型链上的方法都丢了,那我
还要代理干嘛。所以,
Proxy
经过new
之后,指向的依然是target
的原型链。