通过对象深入了解prototype

本文深入讲解JavaScript中对象属性的分类及特性,包括数据属性与访问器属性的区别,如何使用Object.defineProperty进行属性定制,以及如何通过原型链实现方法的继承。

对象属性分为数据属性访问器属性

数据属性

属性特性描述
- configurable(true):能否通过delete删除属性从而重新定义
- enumerable(true):能否通过for-in循环遍历到属性
- writable(true):能否修改属性的值
- value(undefined):包含这个属性的数据值

注:数据属性的设定需使用Object.defineProperty(object,object.key,{writable:…})

坑点,直接通过Object.defineProperty添加的属性,writable默认为false,也就是当前属性默认不可修改

var person = {
    age: 18
};
Object.defineProperty(person, "name", {
    //writable:true,        
    value: "steven"
})
console.log(person.name);   //steven
person.name = 'killer';
使用Object.defineProperty设定的属性默认不可修改
console.log(person.name);   //steven
访问器属性

属性特性描述
- configurable(true):能否通过delete删除属性从而重新定义
- enumerable(true):能否通过for-in循环遍历到属性
- Get(undefined):读取属性时调用函数
- Set(undefined):写入属性是调用函数

注:访问器属性的设定需使用Object.defineProperty(object,object.key,{writable:…})

注:Object.defineProperties可一次访问、设置多条属性

var book={};

Object.defineProperties(book,{
    _year:{
        writable:true,
        value:4000
    },edition:{
        writable:true,
        value:32
    }
});

读取属性特性

var book={};

Object.defineProperties(book,{
    _year:{
        writable:true,
        value:4000
    },edition:{
        writable:true,
        value:32
    }
});
var descriptor=Object.getOwnPropertyDescriptor(book,"_year");
console.log(descriptor.value);  //4000
console.log(descriptor.configurable);   //false
instanceof 对象检测

检测一个对象是否是另一个对象的实例

var arr=new Array();
console.log(arr instanceof Array);  //true
console.log(arr instanceof String); //false

构造函数

构造函数可用来创建特定类新的对象。

//DEMO
function man(name,age,speak){
    this.name=name;
    this.age=age;
    this.describe=function(){
        console.log(name+'said that'+speak);
    };
}
//使用构造函数实例化对象
var man1=new man('steven',20,'do it yourself');

找到实例化成功对象的构造函数

console.log(man1.constructor);  //man函数
console.log(man1.constructor==man); //true

prototype原型模式

只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。

代码示例

//创建函数,给函数给prototype上添加一些属性(可以是值也可以是函数)
function person(){}
person.prototype.name='steven';
person.prototype.age='35';
person.prototype.price='300K';
person.prototype.say=function(){
    console.log('Hello world!');
};
console.log(person.name);

//使用new方法实例化一个pp函数的对象,该函数对象会继承person函数在prototype上面定义的所有方法
var person1=new person();

//当使用继承的属性时会默认查找自身是否定义过相关的方法,如果没定义过会再去其继承的prototype上边查找
console.log(person1.name);  //steven
person1.name='qc';
console.log(person1.name);  //qc

hasOwnProperty判断属性是否来自来自实例

function people () {}
    people.prototype.name='lbsen';
    var people1=new people();
    console.log(people1.hasOwnProperty("name"));    //false
    console.log(people1.name);      //lbsen 来自原型
    people1.name='nicholas';
    console.log(people1.hasOwnProperty("name"));    //true
    console.log(people1.name);      //nicholas 来自实例
    delete.people1.name;
    console.log(people1.name);      //lbsen 来自原型

代码解析

  • 创建函数people,并给people的prototype上绑定name。
  • 创建一个people的实例person1,console发现people1.hasOwnProperty为false,因为hasOwnProperty是用来判断(函数)对象自身是否含有name属性。
  • 给people1的name属性赋值后,people1.hasOwnProperty(“name”)变为true
  • 使用delete删除name后,发现其原型链上的name属性还在,说明delete方法只能删除其自身添加的属性,无法删除通过prototype继承的属性

in判断对象是否包含某属性

console.log('name' in people1);     //true
delete.people1.name;
console.log('name' in people1);     //true

判断people1是否有可用的属性name,无论找到其自身的name属性还是来自prototype的属性,都会返回true,否则返回false

Object.key()枚举属性

function man () {}
    man.prototype.sex='male';
    man.prototype.age='20';
    man.prototype.job='teacher';
    man.prototype.sayName=function(){
        console.log(this.name);
    }

    var man1=new man();
    man1.name='tom';
    man1.height='60kg';
    console.log(Object.keys(man1));
    //["name", "height"] 枚举对象实例属性
    console.log(man1.constructor.prototype);
    //获取到man1原型的prototype方法
    console.log(Object.keys(man1.constructor.prototype));
    //["sex", "age", "job"] 枚举对象原型属性
  • Object.keys(Object) 枚举对象实例属性
  • Object.keys(Object.constructor.prototype) 枚举对象原型属性

原型链的简单封装

    man.prototype.sex='male';
    man.prototype.age='20';
    man.prototype.job='teacher';
    man.prototype.sayName=function(){
        console.log(this.name);
    }

对于以上代码,我们其实可以这么写

man.prototype = {
    sex: 'male',
    age: '20',
    job: 'teacher',
    sayName: function() {
        console.log(this.name);
    }
}

查看各类对象的原生方法(举一反三)

之前利用constructor找到了实例化的对象通过prototype继承的方法,于是我突然想到,平时我们用到的布尔值、字符串、数组、字符串、数字等都属于对象。

平时你一定用过这种方式创建一个空数组。

var arr= new Array();

平时我们用的处理数组的各种方法其实都是基于prototype继承,比如push、shift、pop等等,不信?那就控制台把这些方法都打出来好了

var arr=new Array();

console.log(arr.constructor.prototype);

控制台效果如下,以下就是原声js对于数组对象的所有方法。

有没有感觉醍醐灌顶,如果没有赶紧再看一遍…
控制台输出

除此以外,你还可以用类似的方法查看布尔值、字符串、字符串、数字等对象的原声方法。

var arr=new Array();
console.log(arr.constructor.prototype);

var obj=new Object();
console.log(obj.constructor.prototype);

var num=new Number();
console.log(num.constructor.prototype);

var fun=new Function();
console.log(fun.constructor.prototype);

var bool=new Boolean();
console.log(bool.constructor.prototype);
  • 以上输出的prototype方法的数据类型都是对象
  • 以上对象无法通过for-in循环遍历输出对应方法,因为prototype对象属性的默认配置是enumerable:false
  • 不知道enumerable:false是什么意思的请面壁,然后看看本文最开始关于数据属性特性描述中的内容

END

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值