[Effective JavaScript 笔记]第20长达:使用call方法从定义接收者来调用方法

坏的履

函数或方法的收信人(即绑定到非常重点字this的价)是出于调用者的语法决定的。
方调用语法将计为寻找的目标绑定到this变量,(可参考之前文章《了解函数调用、方法调用及构造函数调用内的异》)。
有时候用用自定义接收者来调用函数,因为该函数或者连无是可望的接收者对象的性。
可以以方作为一个初的习性添加到接收者对象中。使用如下代码:

var obj={
   temporary:function(a,b,c){console.log('obj')} 
}
var f=function(arg1,arg2,arg3){console.log('f')};
var arg1=0,arg2=1,arg3=2;

obj.temporary=f;//标识1
var result=obj.temporary(arg1,arg2,arg3);
delete obj.temporary;

标识1,如果temporary的属于性名在对象吃曾经是,则会对目标造成职能的毁坏。而且取得任何称,都没法保证无与原的目标名重名,可能是目标并无是协调创造的。对象可以针对性能进行冷冻或密封以备修改及长(详细呈现附录)任何新属性。

函数对象call方法

核心描述:用是于一定的作用域下来执行函数,实际上等于设置函数体内this对象的价。
函数对象具备一个放置的章程call来自定义接收者。

f.call(obj,arg1,arg2,arg3)

此行为与一直调用函数自身大一般。

f(arg1,arg2,arg3)

不同点在于,第一单参数指定了一个显式的接收者对象(即指定函数内部this的对准)

1、当调用的不二法门就给删、修改要覆盖时,call方法就可以派上用场了。 因hasOwnProperty方法呢条例,因为这个方式是Object的点子,所有目标都得看调用这个法子。

var obj={
    foo:'good'
};
obj.hasOwnProperty('foo');//true

接下来当这个办法被覆盖时

obj.hasOwnProperty=1;
obj.hasOwnProperty('foo');//Uncaught TypeError: obj.hasOwnProperty is not a function(…)

此时,call方法就是足以派上用场了

var hasOwnProperty={}.hasOwnProperty;
delete obj.hasOwnProperty;
hasOwnProperty.call(obj,'foo');//true
hasOwnProperty.call(obj,'hasOwnProperty');//false

2、定义高阶函数时call方法为专门实用。 高阶函数的一个惯用法是收到一个可选的参数作为调用该函数的接收者。
示范:有一个象征键值对列表的目标,提供了名吧forEach的方式。

var table={
    entries:[],
    addEntry:function(key,value){
        this.entries.push({key:key,value:value});
    },
    forEach:function(f,thisArg){
        var entries=this.entries;
        for(var i=0,n=entries.length;i<n;i++){
            var entry=entries[i];
            f.call(thisArg,entry.key,entry.value,i);
        }
    }
};

地方这事例里容table对象的使用者,将一个方法作为table.forEach的回调函数f,并也该方式供一个合理的收信人。例如,实现将table的始末复制到其它一个蒙。

table1.forEach(table2.addEntry,table2);

俺们将地方的代码直接带地方的代码大家可以晰看到它们的实施进程。

var entries=table1.entries;
for(var i=0,n=entries.length;i<n;i++){
    var entry=entries[i];
    table2.addEntry.call(table2,entry.key,entry.value,i);
}

当时段代码从table2中提取addEntry方法,forEach方法以table2作为接收者,并反复调用该addEntry方法。

提示

  • 行使call方法从定义接收者来调用函数

  • 运call方法好调用在给定的靶子中未有的点子

  • 以call方法定义高阶函数允许使用者给回调函数指定接收者

附录一:对象属性

注:以下内容出自《javascript高级程序设计语言》第3版本

特性类型

ECMAScript-262第5版以概念只有其中才故的风味时,描述了性之表征。描述这些特点是为了促成JS引擎用底,因此js中莫能够一直看它们。为了表示特性是中间价,该标准将她坐了片对准儿方括号中。

例如:[[Enumerable]]。

ECMAScript中产生零星种属性:数据性和访问器属性。

数量性

数性包含一个数据值的职。在此职务好读取和描绘入值。

数据性有4单描述其作为之特色。

  • [[Configurable]]:表示是否通过delete删除属性从而又定义属性,能否修改属性的特征,或者是否拿性能修改也访器属性。
  • [[Enumerable]]:表示是否通过for-in循环返回属性。像前例子中那么直接在对象及定义的性能,它们的是特点默认值为true。
  • [[Writable]]:表示是否修改属性的价值。
  • [[Value]]:包含这个特性的数据值。读取属性值的时段,这个职务读;写副属性值的时候,把新值保存于这位置。这个特性的默认值为undefined。

示例:

var person={
    name:'Nicholas'
}

这边创办的一个称呼吧name的特性,为它指定的价值是’Nicholas’。

也就是说person对象的name属性的[[Value]]特色将于装为’Nicholas’,对是价值的旁改动都用反映在是岗位。

修改属性的法门

改属性默认特性的方,必须采用 ES5的Object.defineProperty()方法。

本条方式接收三独参数:

  • 性能所当的目标
  • 性之讳
  • 一个叙述吻合对象

讲述吻合对象的性能必须是:configurable,enumerable,writable和value。设置中的平或者多单价值,可以改对应之风味值。

例如:

var person={};
Object.defineProperty(preson,'name',{
    writable:false,
    value:'li lei'
});
person.name;//"li lei"
person.name='han mei mei';
person.name;//"li lei"

此地拿name属性设置也特念之属性,所以无法对name进行修改。严格模式下会报错。

脚是一个不行配置的言传身教:

var person={};
Object.defineProperty(preson,'name',{
    configurable:false,
    value:'li lei'
});
person.name;//"li lei"
delete person.name;
person.name;//"li lei"

将configurable设置为false,表示不克起目标中删去属性。如果以严厉模式下,上面的代码会报错。一旦将性能定义也不可配置的,就无可知还管其换回吗而安排的。此时再度调用Object.defineProperty()方法修改除writable之外的性状,都见面招错误。

只顾:在调用Object.defineProperty()方法时,如果非指定,configurable,enumerable,writable特性的默认值都是false。多数气象下,都尚未必要采取Object.defineProperty()方法提供的这些的高等级功能。对于了解js对象十分实用。

走访器属性

做客器属性不带有数据值;它们包含一对儿getter和setter函数(不过,这简单只函数都非是必备的)。

读取访问器属性时,会调用getter函数,这个函数负责返回有效之价值;在写入访问器属性时,会调用setter函数并传新价值,这个函数负责控制哪些处理数量。

拜器属性有如下4只特性:

[[Configurable]]:表示是否通过delete删除属性从而更定义属性,能否修改属性之特性或者是否拿性能修改为多少性。对于直接当目标及定义之习性,这个特点的默认值为true。

[[Enumerable]]:表示是否通过for-in循环返回属性。对于一直以靶及定义之性,这个特点的默认值为true。

[[Get]]:在读取属性时调用的函数。默认值为undefined。

[[Set]]:在形容副属性时调用的函数。默认值为undefined。

访问器属性不能够直接定义,必须用Object.defineProperty()来定义。

示例:

var book={
    _year:2004,
    edition:1
};

Object.defineProperty(book,'year',{
    get:function(){
        return this._year;
    },
    set:function(newVal){
        if(newVal>2004){
            this._year=newVal;
            this.edition+=newVal-2004;
        }
    }
});
book.year=2005;
book.edition;//2
book._year;//2005
book.year;//2005

 定义多个特性

直接上代码

var book={};
Object.defineProperties(book,{
    _year:{
        value:2004
    },
    edition:{
        value:1
    },
    year:{
        get:function(){
            return this._year;
        },
        set:function(newVal){
            if(newVal>2004){
                this._year=newVal;
                this.edition+=newVal-2004;
            }
        }
    }
})

Object.defineProperties()方法,可能通过讲述吻合一糟糕定义多个属性。

接过两单对象参数:

  • 率先只目标是要丰富和改其属性的靶子
  • 亚个对象的性能和第一单目标中只要添加或改动的性质一一对应

读取属性之特征

Object.getOwnPropertyDescriptor()方法,可以取让定属性的叙述称。

吸收两只参数:

  • 性能所于的靶子
  • 苟读博其叙述吻合ECMAScript的性质名称

返回值是一个靶,视性的种类不同,对象的属性也差,具体参见上面的性能类型。

示例

var book={};
Object.defineProperties(book,{
    _year:{
        value:2004
    },
    edition:{
        value:1
    },
    year:{
        get:function(){
            return this._year;
        },
        set:function(newVal){
            if(newVal>2004){
                this._year=newVal;
                this.edition+=newVal-2004;
            }
        }
    }
})
var descriptor=Object.getOwnPropertyDescriptor(book,'_year');
descriptor;//Object {value: 2004, writable: false, enumerable: false, configurable: false}
descriptor=Object.getOwnPropertyDescriptor(book,'year');
descriptor;//Object {configurable:false,enumerable:false,get:function(){...},set:function(newVal){...}