标签:作用域安全的构造函数
说在开头
构造函数一种常见创建对象的模式;构造函数说白了,其实就是一个使用new操作符调用的函数;当被调用时,构造函数内部的指针this会指向新创建的对象;这样新对象就有了新的属性和方法。
常见模式如下:
function Person(name, job, SayHello) { this.name = name; this.job = job; this.SayHello = SayHello; } var person = new Person("jiaxiangjun", "web developer", "SayHello"); person.name;//jiaxiangjun
正如上面所说this指针就指向了对象person;person就有了name,job,SayHello;但是不知道你有没有想过这样的情况。
构造函数,终究还是函数,是函数我们就可以这样调用。
如下:
var person2 = Person("jxj" ,"DBA", "helloKitty");
这种方式调用Person函数this指针实际上指向了window对象;如下:
console.log(window.name);//jxj; console.log(window.job);//DBA; console.log(window.SayHello);//helloKitty;
我相信这不是你的本意吧?甚至,这样会导致window属性的意外增加;在上述例子值window.name被新增或者被修改情况更严重;如果一个页面嵌入了frame,并且很多时候name属性的值用来识别链接目标和frame。
作用域安全的构造函数
作为一个开发工程师,我们有意识的使用了构造函数这种方式;其实,无形中已经默许以后我们要使用构造函数,肯定会使用new的方式;而类似方法调用的方式我们基本不可能这样使用,除非有人误用;所以,我们有理由,我们可以在定义构造函数时,需要做一个容错;或者说,做得更“安全”。也就是博客主题中所说的“作用域安全的构造函数”。
作用域安全的构造函数实际上就是在this指针对文章;this指针类型不是构造函数(instancof Person),比如被指向winow对象时,new一个对象,让构造函数返回一个这个对象。
基本形式如下:
function Person(name, job, weight) { if (this instanceof Person) { this.name = name; this.job = job; this.weight = weight; } else { return new Person(name, job, weight); } } var person3 = Person("jia Sir", "code monkey", "60"); console.log(person3.name);//ia Sir; console.log(person3.job);//code monkey; console.log(person3.weight);//60; var person4 = Person("jia", "coder", "70"); console.log(person4.name);//ia Sir; console.log(person4.job);//code monkey;
这样无论是你直接调用还是使用newc操作符的方式我们都会返回一个person的实例;就避免了污染全局对象。
注意事项
但是有一点需要特殊说明;实现这个模式的时候我们实际上锁定了执行环境中this指针只能指向Person新的实例,也就是可以调用构造函数的环境。那么我们使用call,或者apply这种改变函数作用域的方式实现的继承就有可能被破坏。(也就是如果你使用构造函数窃取模式的继承)。
如下:
function Polygon(sides) { if (this instanceof Polygon) { this.sides = sides; this.getArea = function () { console.log(sides*10); } } else { return new Polygon(sides); } } function Rectangle(width, height) { Polygon.call(this, 2); //console.log(Polygon.call(this, 2).getArea());//这个对象可以调用sides和getArea() this.width = width; this.height = height; //重写getArea方法 this.getArea = function() { console.log(this.width*this.heigh); } } var rect = new Rectangle(15, 20); rect.sides;//undefined
上述代码中,Polygon构造函数是作用域安全的;然而Rectangle构造函数不是的。我们新创建个Rectangle对象之后,this指针指向新创建的对象;但是新创建的对象并不是Polygon的实例;所以想使用Polygon.call(this,2);这种方式来继承Polygon的sides属性,实际上会新创建一个Polygon对象,返回;sides被添加都被返回的对象上了;rect当然也就不能访问到sides了。
如果你使用构造函数窃取结合使用原型链或者寄生组合模式就可以解决这个问题。
如下:
function Polygon(sides) { if (this instanceof Polygon) { this.sides = sides; this.getArea = function () { console.log(sides*10); } } else { return new Polygon(sides); } } function Rectangle(width, height) { Polygon.call(this, 2); //console.log(Polygon.call(this, 2).getArea());//这个对象可以调用sides和getArea() this.width = width; this.height = height; //重写getArea方法 this.getArea = function() { console.log(this.width*this.heigh); } } Rectangle.prototype = new Polygon();//关键代码 var rect = new Rectangle(15, 20); rect.sides;//undefined
上述代码,如果熟悉原型继承那么这行代码,你会很熟悉。如下:
Rectangle.prototype = new Polygon();//关键代码
当然,这意味着一个Rectangle实例也同时是一个Polygon实例;所以,你懂得调用Polygon构造函数时,走到了if的逻辑中了,this就得到了扩充。
总结
So,建议大家使用构造函数时,不妨试一试这种写法;如果面试官看到这段代码,问一下你问什么这么写;那么你表现自己的机会就来啦。
本文出自 “shuizhongyue” 博客,请务必保留此出处http://shuizhongyue.blog.51cto.com/7439523/1663386
标签:作用域安全的构造函数
原文地址:http://shuizhongyue.blog.51cto.com/7439523/1663386