作用域安全的构造函数
属性构造到了window对象
在JavaScript中构造函数其实是一个使用new操作符调用的函数,在使用呢我调用时, 构造函数内部用到的this对象会指向新创建的对象
function Person(name,age,job){ this.name=name; this.age=age; this.job=job; } var person=new Person('Byron',24,'Software Engineer');
在这个例子中构造函数使用this对象给三个属性赋值:name、age、job,当和new操作符连用的时候会创建一个新的Person对象,并给它分配这三个属性。这样没什么问题,问题出在一疏忽忘记使用new操作符来调用构造函数的情况下,由于this对象是在运行期绑定的所以直接调用Person(),this会映射到全局对象window上,导致错误对象属性的意外增加。
var person= Person('Byron',24,'Software Engineer'); alert(window.name); //Byron alert(window.age); //24 alert(window.job); //Software Engineer
这样原本针对Person对象的三个属性被添加window对象,因为构造函数没有通过new操作符调用,而是作为普通函数被调用的,由于this的晚绑定而被解析成window对象。window的那么属性是用来标识链接目标和框架的,这里对该属性的偶然覆盖可能会导致页面上的其它错误,这个问题的解决方法就是创建一个作用域安全的构造函数。
作用域安全构造函数
作用域安全的构造函数在进行属性赋值之前会this对象是否是正确类型的实例,如果不是那么创建新的实例并返回,改造一下上面的构造函数。
function Person(name,age,job){ if(this instanceof Person){ this.name=name; this.age=age; this.job=job; }else{ return new Person(name,age,job); } } var person= Person('Byron',24,'Software Engineer'); alert(window.name); // "" alert(person.name); //Byron alert(person.age); //24 alert(person.job); //Software Engineer
这段代码中Person函数添加了一个检查,确保this对象是Person的实例,如果不是则使用new操作符调用,如果是怎在现在实例内添加属性,这样保证了无论是否显示使用new操作符,都可以正确构造对象。貌似完美了,但是仍旧有问题。
构造函数窃取模式的继承
构造函数窃取模式是常见的一种实现JavaScript继承的方法,做法是在”子类“的构造函数中调用父类的构造函数以实现继承父类属性,这个模式有很多缺陷,这里不做具体说明,和本文内容相关的是这种模式下上面方法所写的构造函数仍旧不安全。
function Polygon(sides){ if(this instanceof Polygon){ this.sides=sides; this.getArea=function(){ return 0; } }else{ return new Polygon(sides); } } function Rectangle(wifth,height){ Polygon.call(this,2); this.width=this.width; this.height=height; this.getArea=function(){ return this.width * this.height; }; } var rect=new Rectangle(5,10); alert(rect.sides); //undefined
在这段代码中,Ploygon的构造函数是安全的,Rectangle的不是,新创建一个Rectangle实例后,这个实例应该通过Polygon.call()来继承sides属性。但是由于Polygon构造函数是安全的,this对象并非Polygon对象实例,构造函数会创建并返回一个新的Polygon实例,而不会把sides属性赋值到this对象上,所以Rectangle对象实例中没有sides属性。我们可以略施小计来解决这个问题
function Polygon(sides){ if(this instanceof Polygon){ this.sides=sides; this.getArea=function(){ return 0; } }else{ return new Polygon(sides); } } function Rectangle(wifth,height){ Polygon.call(this,2); this.width=this.width; this.height=height; this.getArea=function(){ return this.width * this.height; }; } Rectangle.prototype=new
Polygon(); var rect=new Rectangle(5,10); alert(rect.sides); //2
通过重写Rectangle的prototype属性,使它的实例也变成Polygon的实例,这样既更像是继承一些,也解决了上面问题。
作用
看起来作用域安全的构造函数很没有市场的样子,很多人会说只要写代码的时候小心些就可以了,但是JavaScript的特点决定了其不能够在编译期发现错误,而在多个程序员开发一个页面的时候,作用域安全的构造函数就很有用了,我们不能保证每个人写的代码都那么小心,如果一个人代码出错,影响到全局属性,那么这种错误难以追踪调试,这时候使用作用域安全的构造函数就可以避免此类问题。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义