js高级程序设计学习的高级函数

康宁之项目检测

function isArray(value){
    return Object.prototype.toString.call(value) === "[object Array]";
}

function isFunction(value){
    return Object.prototype.toString.call(value) === "[object Function]";
}

//检测原生JSON对象
function isRegExp(value){
    return Object.prototype.toString.call(value) === "[object RegExp]";
}

var isNativeJson = window.JSON && Object.prototype.toString.call(JSON) === "[object JSON]";

而是如果小心Object.prototype.toString本身也许被改写。

作用域安全的构造函数

当以new调用构造函数时,构造函数内用到的this对象见面针对新创的目标实例,如:

function Person (name) {
    this.name = name;
}
var person = new Person("oliver");
console.log(person.name);

题材是当没有采用new操作符,直接调用构造函数,this会映射到全局对象window上,导致错误对象属性的不测加:

function Person (name) {
    this.name = name;
}
var person = Person("oliver");
console.log(window.name); //oliver

解决办法是创立一个作用域安全之构造函数:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
var person1 = Person("oliver");
console.log(person1.name); //oliver
var person2 = new Person("troy");
console.log(person2.name); //troy
console.log(window.name); //""

但是,如果用构造函数窃取模式之接续且未实用原型链,那么这延续很可能被毁掉使:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
function People (name,age) {
    Person.call(this, name);
    this.age = age;
}
var p = new People("Oliver", 18);
console.log(p.name); //undefined
console.log(p.age); //18

结使用原型链或者寄生组合则可缓解此问题:

function Person(name) {
    if (this instanceof Person) { //如果this是Person的实例
        this.name = name;
    } else {
        return new Person(name); //否则调用new操作符
    }
}
function People (name,age) {
    Person.call(this, name);
    this.age = age;
}
People.prototype = new Person(); //关键点
var p = new People("Oliver", 18);
console.log(p.name); //Oliver
console.log(p.age); //18

惰性载入函数

惰性函数表示函数执行的支行就会发生同样次。有少数栽实现惰性载入函数的方法,第一种植就是是在函数被调用时在处理函数。在第一糟调用的经过被,该函数被盖也外一个准适用方式实施之函数,这样任何针对本来函数的调用就毫无再通过实践的分段了。

function createXHR () {
    if (typeof XMLHttpRequest !== "undefined") {
        createXHR = function () { //关键点
            return new XMLHttpRequest();
        }
    } else if (typeof ActiveXObject !== "undefined") {
        createXHR = function () { //关键点
            return new ActiveXObject(["MSXML2.XMLHttp"]);
        }
    } else {
        createXHR = function () { //关键点
            throw new Error("No XHR object available.");
        }
    }
    return createXHR(); //关键点
}

第二种植实现惰性载入函数的计尽管是当宣称函数时即指定适当的函数。这样,第一次等调用函数时便不见面损失性能了,而于代码首次于加载时见面损失有性质。

var createXHR = (function() {
    if (typeof XMLHttpRequest !== "undefined") {
        return function () { //关键点
            return new XMLHttpRequest();
        }
    } else if (typeof ActiveXObject !== "undefined") {
        return function () { //关键点
            return new ActiveXObject(["MSXML2.XMLHttp"]);
        }
    } else {
        return function () { //关键点
            throw new Error("No XHR object available.");
        }
    }
})();

以此事例中利用的技巧是创办一个匿名、自实行之函数,用以确定该运用啊一个函数实现。

函数绑定

函数绑定要创造一个函数,可以当一定的this环境中以指定参数调用另一个函数。该技能常常与回调函数和事件处理程序并使用,
以便在拿函数作为变量传递的以保留代码的施行环境。

var handler = {
  message: "Event handled",
  handleClick: function(event){
    console.log(this.message);
  }
};

handler.handleClick();

var a = handler.handleClick;
a();

var btn1 = document.getElementById('my-btn1');
btn1.addEventListener('click',handler.handleClick,false);

var btn2 = document.getElementById('my-btn2');
btn2.addEventListener('click',function(){
  handler.handleClick();
},false);

btn1点击后显示undefined,btn2利用闭包来修正这个问题

是因为代码之中存在着this变量,而this在目前条件下本着确定的对象,但是当更改代码的履行环境时,就会产出问题了。为了解决这个题材,
javascript函数库中贯彻了一个bind() 函数来化解此问题。

一个略的bind() 函数接收一个函数和一个条件,
并返回一个在加以环境遭受调用给定函数的函数,
并且将拥有参数原封无动传递过去。 语法如下:

function bind(fn, context) {
    return function() {
        return fn.apply(context, arguments);
    }
}

留神这里用的arguments并无是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));

ECMAScript5也具函数定义了一个原生的bind() 方法, 进一步简化了操作。

var handler = {
    message: "Event handled",
    handleClick: function(event) {
        alert(this.message);
    }
};
var btn = document.getElementById("my-btn");
EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler));

它主要用于事件处理程序和setTimeout() 和setInterval()。
然而让绑定函数和常见函数相比有再次多之开发, 它们要再多内存,
同时为坐多重新函数调用稍微放缓有, 所以最好才当必要经常行使。

函数柯里化

她用来创造已经安装好了一个还是多独参数的函数。 函数柯里化的骨干方式是:
使用一个闭包返回一个函数。 当函数被调用时,
返回的函数还索要装有传来的参数。

柯里化函数通常由以下步骤动态的开创:
调用别样一个函数ECMAScript并为它传播要柯里化的函数和必备参数。
下面是创造柯里化函数的通用方:

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);
    }
}

函数柯里化还经常作为函数绑定的同有些含在其间,构造出更为复杂的bind函数

function bind(fn,contenxt) {
    var args = Array.prototype.slice.call(arguments,2);
    return function() {
        var innerArgs = Array.prototype.slice.call(arguments);
        var finalArgs = args.cancat(innerArgs);
        return fn.apply(context,finalArgs);
    }
}

当您想除了event对象还额外为事件处理程序传递参数时,这不行有效。

EventUtil.addHandler(btn, "click", bind(handler.handleClick,handler,"my-btn")); 

ES5的bind方法吗落实了函数柯里化,只需要以this值后更招另一个参数

EventUtil.addHandler(btn, "click", handler.handleClick.bind(handler,"my-btn"));

函数绑定和柯里化都非应滥用,因为每个函数会带来格外的开