资讯专栏INFORMATION COLUMN

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

jasperyang / 2094人阅读

摘要:的使用对象是由多个名值对组成的无序的集合。目标属性所拥有的特性返回值传入函数的对象。是一种获得属性值的方法是一种设置属性值的方法。参考相关阅读链接基础篇中的可枚举属性与不可枚举属性以及扩展

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://www.ucloud.cn/yun/87005.html

相关文章

  • JS基础--HTML DOM classList 属性

    摘要:使用,程序员还可以用它来判断某个节点是否被赋予了某个类。现在是增加现在是删除是否存在类检查是否含有某个类结果是或者。属性返回类列表中类的数量。查看元素有多少个类名获取获取元素的所有类名返回类名在元素中的索引值。 页面DOM里的每个节点上都有一个classList对象,程序员可以使用里面的方法新增、删除、修改节点上的CSS类。使用classList,程序员还可以用它来判断某个节点是否被赋...

    snowell 评论0 收藏0
  • JS基础--JS可枚举属性与不可枚举属性以及扩展

    摘要:在中,对象的属性分为可枚举和不可枚举之分,它们是由属性的值决定的。这是因为中内置的属性是不可枚举的,所以不能被访问到。此对象不可扩展且指定的属性名称不存在。返回值一个数组,其中包含对象的可枚举属性和方法的名称。 在JavaScript中,对象的属性分为可枚举和不可枚举之分,它们是由属性的enumerable值决定的。可枚举性决定了这个属性能否被for…in查找遍历到。 一、怎么判断属性...

    dreamans 评论0 收藏0
  • Webpack Loader 高手进阶(二)

    摘要:如果函数没有返回值的话,那么进入到下一个的函数的执行阶段。这也是异步化的一种方式如果执行后有返回值,执行开始下一个执行以上就是对于在构建过程中执行流程的源码分析。 文章首发于个人github blog: Biu-blog,欢迎大家关注~ Webpack 系列文章: Webpack Loader 高手进阶(一)Webpack Loader 高手进阶(二)Webpack Loader 高手...

    jackzou 评论0 收藏0
  • should.js源码分析与学习

    摘要:结构其中为整个项目入口,为中的类,负责对测试信息进行记录。通过抛出错误而不是返回布尔值的方式来通知用户,能够更加明显的通知用户,也方便向上抛出异常进行传递。 背景 为了研究与学习某些测试框架的工作原理,同时也为了完成培训中实现一个简单的测试框架的原因,我对should.js的代码进行了学习与分析,现在与大家来进行交流下。 目录 ext assertion.js assertion-e...

    Turbo 评论0 收藏0
  • 进阶4-2期】Object.assign 原理及其实现

    摘要:木易杨注意原始类型被包装为对象木易杨原始类型会被包装,和会被忽略。木易杨原因在于时,其属性描述符为不可写,即。木易杨解决方法也很简单,使用我们在进阶期中介绍的就可以了,使用如下。 引言 上篇文章介绍了赋值、浅拷贝和深拷贝,其中介绍了很多赋值和浅拷贝的相关知识以及两者区别,限于篇幅只介绍了一种常用深拷贝方案。 本篇文章会先介绍浅拷贝 Object.assign 的实现原理,然后带你手动实...

    layman 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<