提醒:本文发布于 3430 天前,文章内容可能 因技术时效性过期 或 被重新修改,请谨慎参考。
作用域安全的构造函数
这是常见的构造函数:
function Person(name, age, job){ this.name = name; this.age = age; this.job = job; } var person = new Person("Nicholas", 29, "Software Engineer");
|
假设:
var person1 = Person("test",22,"FE");
|
那么 这个新对象的属性将会被绑定在window对象上面, 如果当前环境存在 window.name的操作 那么可能就会造成错误.
解决方法:(域安全的构造函数)
先判断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 person1 = Person("Nicholas", 29, "Software Engineer"); alert(window.name); alert(person1.name); var person2 = new Person("Shelby", 34, "Ergonomist"); alert(person2.name);
|
缺点:
function Polygon(sides){ if (this instanceof Polygon) { this.sides = sides; this.getArea = function(){ return 0; }; } else { return new Polygon(sides); } } function Rectangle(width, height){ Polygon.call(this, 2); this.width = width; this.height = height; this.getArea = function(){ return this.width * this.height; }; } var rect = new Rectangle(5, 10); alert(rect.sides);
|
改正方法: 利用原型链
function Polygon(sides){ if (this instanceof Polygon) { this.sides = sides; this.getArea = function(){ return 0; }; } else { return new Polygon(sides); } } function Rectangle(width, height){ Polygon.call(this, 2); this.width = 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);
|
函数加载优化技巧
普通情况下调用函数:
function createXHR() { if (typeof XMLHttpRequest != "undefined") { return new XMLHttpRequest(); } else if (typeof ActiveXObject != "undefined") { if (typeof arguments.callee.activeXString != "string") { var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len; for (i = 0, len = versions.length; i < len; i++) { try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex) { } } } return new ActiveXObject(arguments.callee.activeXString); } else { throw new Error("No XHR object available."); } }
|
缺点:每一次判断和循环造成性能上的损失
解决方案:惰性载入(1)
执行代码的时候损失性能
function createXHR(){ if (typeof XMLHttpRequest != "undefined"){ createXHR = function(){ return new XMLHttpRequest(); }; } else if (typeof ActiveXObject != "undefined"){ createXHR = function(){ if (typeof arguments.callee.activeXString != "string"){ var versions = [ "MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp" ], i, len; for (i=0,len=versions.length; i < len; i++){ try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex){ } } } return new ActiveXObject(arguments.callee.activeXString); }; } else { createXHR = function(){ throw new Error("No XHR object available."); }; } return createXHR(); }
|
解决方案:惰性载入(2)
var createXHR = (function () { if (typeof XMLHttpRequest != "undefined") { return function () { return new XMLHttpRequest(); }; } else if (typeof ActiveXObject != "undefined") { return function () { if (typeof arguments.callee.activeXString != "string") { var versions = ["MSXML2.XMLHttp.6.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp"], i, len; for (i = 0, len = versions.length; i < len; i++) { try { new ActiveXObject(versions[i]); arguments.callee.activeXString = versions[i]; break; } catch (ex) { } } } return new ActiveXObject(arguments.callee.activeXString); }; } else { return function () { throw new Error("No XHR object available."); }; } })();
|
函数绑定
常见问题
var handler = { message: "Event handled", handleClick: function(event){ alert(this.message); } }; var btn = document.getElementById("my-btn"); EventUtil.addHandler(btn, "click", handler.handleClick);
|
改进:
var handler = { message: "Event handled", handleClick: function(event){ alert(this.message); } }; var btn = document.getElementById("my-btn"); EventUtil.addHandler(btn, "click", function(event){ handler.handleClick(event); });
|
这个解决方案在 onclick 事件处理程序内使用了一个闭包直接调用 handler.handleClick()。
当然,这是特定于这段代码的解决方案。创建多个闭包可能会令代码变得难于理解和调试。因此,很多JavaScript 库实现了一个可以将函数绑定到指定环境的函数。这个函数一般都叫 bind()。一个简单的 bind()函数接受一个函数和一个环境,并返回一个在给定环境中调用给定函数的函数,并且将所有参数原封不动传递过去。
语法如下:
function bind(fn, context){ return function(){ return fn.apply(context, arguments); }; }
|
这个函数似乎简单,但其功能是非常强大的。在 bind()中创建了一个闭包,闭包使用 apply()调用传入的函数,并给 apply()传递 context 对象和参数。注意这里使用的 arguments 对象是内部函数的,而非 bind()的。当调用返回的函数时,它会在给定环境中执行被传入的函数并给出所有参数。
bind()函数按如下方式使用:
var handler = { message: "Event handled", handleClick: function(event){ alert(this.message); } }; var btn = document.getElementById("my-btn"); EventUtil.addHandler(btn, "click", bind(handler.handleClick, handler));
|
ECMAS5: 存在bind方法, 但IE9及以上支持
var handler = { message: "Event handled", handleClick: function(event){ alert(this.message + ":" + event.type); } }; var btn = document.getElementById("my-btn"); EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));
|
函数curry化
函数柯里化(function currying) ,它用于创建已经设置好了一个或多个参数的函数。函数柯里化的基本方法和 函数绑定 是一样的:使用一个闭包返回一个函数。两者的区别在于,当函数被调用时,返回的函数还需要设置一些传入的参数。
function add(num1, num2){ return num1 + num2; } function curriedAdd(num2){ return add(5, num2); } alert(add(2, 3)); alert(curriedAdd(3));
|
柯里化函数通常由以下步骤动态创建:调用另一个函数并为它传入要柯里化的函数和必要参数。下面是创建柯里化函数的通用方式。
function curry(fn){ var args = Array.prototype.slice.call(arguments, 1); return function(){ var innerArgs = Array.prototype.slice.call(arguments); var finalArgs = args.concat(innerArgs); return fn.apply(null, finalArgs); }; }
|
防篡改对象
不过请注意:一旦把对象定义为防篡改,就无法撤销了
不可扩展对象:(第一个级别的保护)
默认情况下,所有对象都是可以扩展的。也就是说,任何时候都可以向对象中添加属性和方法。
var person = { name: "Nicholas" }; person.age = 29;
|
即使第一行代码已经完整定义 person 对象,但第二行代码仍然能给它添加属性。现在,使用Object.preventExtensions()方法可以改变这个行为,让你不能再给对象添加属性和方法。
例如:
var person = { name: "Nicholas" }; Object.preventExtensions(person); person.age = 29; alert(person.age);
|
虽然不能给对象添加新成员,但已有的成员则丝毫不受影响。你仍然还可以修改和删除已有的成员。另外,使用 Object.istExtensible()方法还可以确定对象是否可以扩展。
var person = { name: "Nicholas" }; alert(Object.isExtensible(person)); Object.preventExtensions(person); alert(Object.isExtensible(person));
|
密封的对象(第二个级别的保护)
var person = { name: "Nicholas" }; Object.seal(person); person.age = 29; alert(person.age); delete person.name; alert(person.name);
var person = { name: "Nicholas" }; alert(Object.isExtensible(person)); alert(Object.isSealed(person)); Object.seal(person); alert(Object.isExtensible(person)); alert(Object.isSealed(person));
|
冻结的对象(第三个级别的保护)
var person = { name: "Nicholas" }; Object.freeze(person); person.age = 29; alert(person.age); delete person.name; alert(person.name); person.name = "Greg"; alert(person.name);
var person = { name: "Nicholas" }; alert(Object.isExtensible(person)); alert(Object.isSealed(person)); alert(Object.isFrozen(person)); Object.freeze(person); alert(Object.isExtensible(person)); alert(Object.isSealed(person)); alert(Object.isFrozen(person));
|
访客评论