JS进阶篇--JS apply的奇妙用法以及扩展到Object.defineProperty的运用

Math.max 完成取得数组中最大的一项

var array = [1,2,3,4,5];
var max = Math.max.apply(null, array);
console.log(max); // 5

挪用的时刻第一个参数给了一个null,这个是因为没有对象去挪用这个要领,只须要用这个要领协助运算,取得返回的效果就行,所以直接传递了一个null过去。

Math.min 完成取得数组中最小的一项

var array = [1,2,3,4,5];
var min= Math.min.apply(null, array);
console.log(min); // 1

##在原生对象上面增加max与min要领
那就会须要用到原生对象要领Object.defineProperty(),会直接在一个对象上定义一个新属性,或许修正一个对象的现有属性, 并返回这个对象。

Object.defineProperty(Array.prototype, 'max', {  
    writable: false,  
    enumerable: false,  
    configurable: true,  
    value: function () {  
        return Math.max.apply(null, this);  
    }  
});  
  
Object.defineProperty(Array.prototype, 'min', {  
    writable: false,  
    enumerable: false,  
    configurable: true,  
    value: function () {  
        return Math.min.apply(null, this);  
    }  
});

直接在数组上挪用即可:

var arr = [54,545,2165,545,56];  
console.log(arr.max()); //2165 
console.log(arr.min()); //54

上面讲到了Object.defineProperty的要领,下面我们来理解下。

Object.defineProperty的运用

对象是由多个名/值对构成的无序的鸠合。对象中每一个属性对应恣意范例的值。定义对象能够运用组织函数或字面量的情势:

var obj = new Object;  //obj = {}
obj.name = "张三";  //增加形貌
obj.say = function(){};  //增加行动

除了以上增加属性的体式格局,还能够运用Object.defineProperty定义新属性或修正原有的属性。

Object.defineProperty()形貌

语法:Object.defineProperty(obj, prop, descriptor)

参数申明:

  • obj:必需。目的对象
  • prop:必需。需定义或修正的属性的名字
  • descriptor:必需。目的属性所具有的特征

返回值:

  • 传入函数的对象。即第一个参数obj

针对属性,我们能够给这个属性设置一些特征,比方是不是只读不能够写;是不是能够被for..inObject.keys()遍历。

给对象的属性增加特征形貌,现在供应两种情势:数据形貌和存取器形貌。

数据形貌

当修正或定义对象的某个属性的时刻,给这个属性增加一些特征:

var obj = {
    test:"hello"
}
//对象已有的属性增加特征形貌
Object.defineProperty(obj,"test",{
    configurable:true | false,
    enumerable:true | false,
    value:恣意范例的值,
    writable:true | false
});
//对象新增加的属性的特征形貌
Object.defineProperty(obj,"newKey",{
    configurable:true | false,
    enumerable:true | false,
    value:恣意范例的值,
    writable:true | false
});

数据形貌中的属性都是可选的,来看一下设置每一个属性的作用。

value

属性对应的值,能够使恣意范例的值,默以为undefined

var obj = {}
//第一种状况:不设置value属性
Object.defineProperty(obj,"newKey",{

});
console.log( obj.newKey );  //undefined
------------------------------
//第二种状况:设置value属性
Object.defineProperty(obj,"newKey",{
    value:"hello"
});
console.log( obj.newKey );  //hello

####writable
属性的值是不是能够被重写。设置为true能够被重写;设置为false,不能被重写。默以为false。

var obj = {}
//第一种状况:writable设置为false,不能重写。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false
});
//变动newKey的值
obj.newKey = "change value";
console.log( obj.newKey );  //hello

//第二种状况:writable设置为true,能够重写
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true
});
//变动newKey的值
obj.newKey = "change value";
console.log( obj.newKey );  //change value

####enumerable
此属性是不是能够被罗列(运用for…in或Object.keys())。设置为true能够被罗列;设置为false,不能被罗列。默以为false。

var obj = {}
//第一种状况:enumerable设置为false,不能被罗列。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false
});

//罗列对象的属性
for( var attr in obj ){
    console.log( attr );  
}
//第二种状况:enumerable设置为true,能够被罗列。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:true
});

//罗列对象的属性
for( var attr in obj ){
    console.log( attr );  //newKey
}

####configurable
是不是能够删除目的属性或是不是能够再次修正属性的特征(writable, configurable, enumerable)。设置为true能够被删除或能够从新设置特征;设置为false,不能被删除或不能够从新设置特征。默以为false。

这个属性起到两个作用:

  • 目的属性是不是能够运用delete删除
  • 目的属性是不是能够再次设置特征
//-----------------测试目的属性是不是能被删除------------------------
var obj = {}
//第一种状况:configurable设置为false,不能被删除。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:false
});
//删除属性
delete obj.newKey;
console.log( obj.newKey ); //hello

//第二种状况:configurable设置为true,能够被删除。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:true
});
//删除属性
delete obj.newKey;
console.log( obj.newKey ); //undefined

//-----------------测试是不是能够再次修正特征------------------------
var obj = {}
//第一种状况:configurable设置为false,不能再次修正特征。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:false
});

//从新修正特征
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true,
    enumerable:true,
    configurable:true
});
console.log( obj.newKey ); //报错:Uncaught TypeError: Cannot redefine property: newKey

//第二种状况:configurable设置为true,能够再次修正特征。
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:false,
    enumerable:false,
    configurable:true
});

//从新修正特征
Object.defineProperty(obj,"newKey",{
    value:"hello",
    writable:true,
    enumerable:true,
    configurable:true
});
console.log( obj.newKey ); //hello

除了能够给新定义的属性设置特征,也能够给已有的属性设置特征

//定义对象的时刻增加的属性,是可删除、可重写、可罗列的。
var obj = {
    test:"hello"
}

//改写值
obj.test = 'change value';

console.log( obj.test ); //'change value'

Object.defineProperty(obj,"test",{
    writable:false
})


//再次改写值
obj.test = 'change value again';

console.log( obj.test ); //依然是:'change value'

> 提醒:一旦运用Object.defineProperty给对象增加属性,那末假如不设置属性的特征,那末configurableenumerablewritable这些值都为默许的false

var obj = {};
//定义的新属性后,这个属性的特征中configurable,enumerable,writable都为默许的值false
//这就致使了newkey这个是不能重写、不能罗列、不能再次设置特征
//
Object.defineProperty(obj,'newKey',{

});

//设置值
obj.newKey = 'hello';
console.log(obj.newKey);  //undefined

//罗列
for( var attr in obj ){
    console.log(attr);
}

设置的特征总结:

  • value: 设置属性的值
  • writable: 值是不是能够重写。true | false
  • enumerable: 目的属性是不是能够被罗列。true | false
  • configurable: 目的属性是不是能够被删除或是不是能够再次修正特征 true | false

存取器形貌

当运用存取器形貌属性的特征的时刻,许可设置以下特征属性:

var obj = {};
Object.defineProperty(obj,"newKey",{
    get:function (){} | undefined,
    set:function (value){} | undefined
    configurable: true | false
    enumerable: true | false
});

> 注重:当运用了getter或setter要领,不许可运用writable和value这两个属性

getter/setter

当设置或猎取对象的某个属性的值的时刻,能够供应getter/setter要领。

  • getter 是一种取得属性值的要领
  • setter是一种设置属性值的要领。

在特征中运用get/set属性来定义对应的要领。

var obj = {};
var initValue = 'hello';
Object.defineProperty(obj,"newKey",{
    get:function (){
        //当猎取值的时刻触发的函数
        return initValue;    
    },
    set:function (value){
        //当设置值的时刻触发的函数,设置的新值经由过程参数value拿到
        initValue = value;
    }
});
//猎取值
console.log( obj.newKey );  //hello

//设置值
obj.newKey = 'change value';

console.log( obj.newKey ); //change value

> 注重:get或set不是必需成对涌现,任写其一就能够。假如不设置要领,则get和set的默许值为undefined

经由过程Object.defineProperty给一个对象的某个属性增加多个要领,以下例子:

var obj = {};
Object.defineProperty(obj,'atrr',{
    get:function(){
        var self = this;
        var num = 0;
        return {
            add:function(value){
                return num + value;
            },
            reduce:function(value){
                return num - value;
            }
        }
    }
});

console.log(obj.atrr.add(5)); //5
console.log(obj.atrr.add(8)); //8
console.log(obj.atrr.reduce(8));  //-8

申明:在obj对象的atrr对象上增加了两个要领add与reduce.

兼容性

在ie8下只能在DOM对象上运用,尝试在原生的对象运用 Object.defineProperty()会报错。

参考

Object.defineProperty()

相干浏览链接:《JS基本篇–JS中的可罗列属性与不可罗列属性以及扩大 》

    原文作者:风雨后见彩虹
    原文地址: https://segmentfault.com/a/1190000009717325
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞