文档章节

关于JavaScript原型属性若干特点的分析

前端二牛
 前端二牛
发布于 2018/10/27 22:35
字数 1527
阅读 17
收藏 1

1. delete关键字

对象属性会屏蔽原型属性,通过delete删除对象的属性,可以继续访问原型属性,达到解除屏蔽的目的,看如下代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p1 = new Person('张三', 18, 'JavaScript');

p1.sayName = function(){
    console.log('没有名字');
}
p1.sayName();//没有名字

//删除对象属性,可以继续访问到原型上的属性
delete p1.sayName;
p1.sayName();//张三

如代码所示,给p1添加了sayName方法,屏蔽掉了原型上的sayName,通过delete关键字删除对象上的属性,又可以访问到原型上的属性了。

2. hasOwnProperty()

当给定属性存在于实例中时,返回true,否则返回false,看下面代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p1 = new Person('张三', 18, 'JavaScript');
var p2 = new Person('李四', 18, 'Java');

p1.sayName = function(){
    console.log('没有名字');
}

console.log(p1.hasOwnProperty('sayName'));//true
console.log(p2.hasOwnProperty('sayName'));//false

如代码所示,给p1添加了sayName方法,通过hasOwnProperty检测的结果为true,没有给p2添加,检测结果为falsehasOwnProperty只关心实例对象有没有这个属性,有就返回true,没有就返回false,不管原型有没有。

3. in关键字

只要通过实例对象能够访问到的属性,in关键字就返回true,怎么理解呢?看下面代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('张三', 18, 'JavaScript');

console.log(p.hasOwnProperty('name'));//true
console.log(p.hasOwnProperty('sayName'));//false

console.log('name' in p);//true
console.log('sayName' in p);//true

delete p.name;

console.log(p.hasOwnProperty('name'));//false
console.log('name' in p);//false

如代码所示,hasOwnProperty只有属性在实例中存在时才会返回truenamesayName通过实例都是可访问的,所以使用in检测时结果为truein关键字,只要通过实例能访问到属性就返回true,也就是说,不管属性存在实例还是原型中,in关键字都会返回true,而hasOwnProperty只有当属性存在实例中才会返回true

这样结合二者我们也可以自定义一个判断属性只存在原型中的方法了,如下代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    },
    /*
    * param: property, 类型:String, 描述:属性
    * return: 类型:Boolean,描述:返回true,属性只存在原型中
    * */
    hasPrototypeProperty: function(property){
        return (property in this) && !this.hasOwnProperty(property);
    }
};

var p = new Person('张三', 18, 'JavaScript');

console.log(p.hasPrototypeProperty('name'));//false, name不存在原型中
console.log(p.hasPrototypeProperty('sayName'));//true, sayName只存在原型中

p.sayName = function(){
    console.log('没有名字');
}

console.log(p.hasPrototypeProperty('sayName'));//false, sayName不是只在原型中存在

如代码所示,重写原型时添加了一个方法,用于判断属性是否只在原型中存在。首先使用in关键字判断属性在实例或原型中存在,再使用hasOwnProperty()排除掉在实例中存在的情况,这样结果返回true时就表示该属性只在原型中存在了。

4. 枚举属性

4.1 for-in枚举

可以枚举出所有能够通过对象访问的、可枚举的属性。能够通过对象访问的属性好理解,那什么样的属性算可枚举的属性呢?目前读者只要记住所有开发人员定义的属性都是可枚举的就好了,如下代码所示:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('张三', 18, 'JavaScript');

for(var pro in p){
    console.log(pro);//name age job friends constructor sayName
}

4.2 Object.keys()方法

ES5新增的方法,这个方法接收一个对象作为参数,可枚举该对象本身所有可枚举的属性,不包括原型,见如下代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('张三', 18, 'JavaScript');

console.log(Object.keys(p));//["name", "age", "job", "friends"]
console.log(Object.keys(Person));//[]
console.log(Object.keys(Person.prototype));//["constructor", "sayName"]

如代码所示,枚举的只是对象本身的属性,不是能通过对象访问的属性都可枚举,这点要注意和for-in进行比较。

4.3 Object.getOwnPropertyNames()

这个方法可以枚举所有属性,无论是不是可枚举的,只有一个例外——__proto__,见如下代码:

function Person(name, age, job){
    this.name = name;
    this.age = age;
    this.job = job;
    this.friends = ['小明', '小刚'];
}

Person.prototype = {
    constructor: Person,
    sayName: function(){
        console.log(this.name);
    }
};

var p = new Person('张三', 18, 'JavaScript');

console.log(Object.getOwnPropertyNames(p));//["name", "age", "job", "friends"]
console.log(Object.getOwnPropertyNames(Person));//["length", "name", "arguments", "caller", "prototype"]
console.log(Object.getOwnPropertyNames(Person.prototype));//["constructor", "sayName"]

5. 原生对象的原型

所有原生引用类型(ArrayStringDate等)都在其构造函数的原型上定义了方法。学习了原型的知识,我们也可以在原型上扩展方法,如下代码所示:

Date.prototype.addDay = function (count) {
    return new Date(this.getFullYear(), this.getMonth(), this.getDate() + count);
}

var _date = new Date();
console.log(_date.addDay(2));//Mon Oct 29 2018 00:00:00 GMT+0800 (中国标准时间),后天
console.log(_date.addDay(-1));//Fri Oct 26 2018 00:00:00 GMT+0800 (中国标准时间),昨天

如代码所示,给Date添加了一个加几天的方法,这样做很方便,但是原书中有这样一段话,“尽管可以这样做,但我们不推荐在产品化的程序中修改原生对象的原型。如果因某个实现中缺少某个方法,就在原生对象的原型中添加这个方法,那么当在另一个支持该方法的实现中运行代码时,就可能会导致命名冲突。而且,这样做也可能会意外地重写原生方法”。

虽然作者这样说,但是工作中依然会有人这么写,也确实方便,我就遇到过很多次,这个还是在工作中具体情况具体分析吧。

本文参考《JavaScript高级程序设计(第3版)》

© 著作权归作者所有

共有 人打赏支持
前端二牛
粉丝 23
博文 86
码字总数 47062
作品 0
浦东
高级程序员
私信 提问
关于javascript的原型和原型链,看我就够了(三)

温故 我们先回顾一下前两天讨论的内容 创建对象的三种方式 通过对象直接量 通过new创建对象 通过Object.create() js中对象分为两种 函数对象 普通对象 原型对象prototype 每一个函数对象都有...

陌上寒
2018/11/04
0
0
全面理解面向对象的 JavaScript

简介: JavaScript 函数式脚本语言特性以及其看似随意的编写风格,导致长期以来人们对这一门语言的误解,即认为 JavaScript 不是一门面向对象的语言,或者只是部分具备一些面向对象的特征。本...

IBMdW
2013/04/21
1K
6
关于javascript的原型和原型链,看我就够了(一)

关于js的原型和原型链,有人觉得这是很头疼的一块知识点,其实不然,它很基础,不信,往下看 要了解原型和原型链,我们得先从对象说起 创建对象 创建对象的三种方式: 对象直接量 通过对象直...

陌上寒
2018/11/03
0
0
JavaScript系列-JavaScript之原型和原型链

一、概述 JavaScript ,是一种面向对象的程序设计语言,但是 JS 本身是没有 “类” 的概念,JS 是靠原型和原型链实现对象属性的“继承”。 在理解原型前,需要先知道实例对象的构造函数是什么...

大灰狼的小绵羊哥哥
02/23
0
0
用通俗易懂的语言介绍JavaScript原型

原型(prototype)是每个JavaScript开发人员必须理解的基本概念,本文的目标是通俗而又详细地解释JavaScript的原型。如果你读完这篇博文以后还是不理解JavaScript的原型,请将你的问题写在下...

gsbhzh
2014/10/29
0
0

没有更多内容

加载失败,请刷新页面

加载更多

维信小程序button样式重写

一、小程序button默认按钮样式重写 以primary按钮为例: /**重写默认按钮样式**/button[type='primary'] {background: red;padding: 5px 0px;line-height: 30px;font-size: 14px;......

tianma3798
36分钟前
2
0
使用async和await封装vue中的http请求

实际需求中经常会碰到想异步请求代码写的像同步一样简洁,解决回调地狱,这是最近封装的一个。 // import qs from 'qs';import axios from 'axios'import utils from './util'import { To......

chinahufei
43分钟前
1
1
python中类方法和静态方法区别

面相对象程序设计中,类方法和静态方法是经常用到的两个术语。 逻辑上讲:类方法是只能由类名调用;静态方法可以由类名或对象名进行调用。 在C++中,静态方法与类方法逻辑上是等价的,只有一...

Linux就该这么学
49分钟前
2
0
5G是现实的狂欢还是骨感?

“4G改变生活,5G改变社会。” 这一句充满无限遐想的口号,因2019年世界移动大会(MWC2019)召开带来的产业最前沿动态,让观察者、消费者产生梦想照进现实的感觉。OPPO、小米、华为、三星、LG、...

linuxCool
52分钟前
2
0
Codis的dashboard异常退出后,重新启动报异常的处理方法

dashboard是codis的核心组建,所有集群相关的操作都是通过dashboard进行的。如果dashboard出现宕机、服务被杀掉等极端情况,则会导致codis集群无法使用。 1)codis集群维护时,需要关闭dashb...

linxyz
53分钟前
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部