继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

js基础之原型(构造函数、原型和实例之间的那些属性)

哔哔one
关注TA
已关注
手记 463
粉丝 93
获赞 543

先看一张图!展示了构造函数、原型和实例之间的关系。

590

由相互关联的原型组成的链状结构就是原型链

从图中可看出,js 中与原型相关的属性:对象有 [[prototype]]属性(内部属性)、函数对象有prototype属性、原型对象有constructor属性。

[[prototype]]

在 JavaScript 中,原型也是一个对象,通过原型可以实现对象的属性继承,JavaScript 的对象中都包含了一个" [[Prototype]]"内部属性,这个属性所对应的就是该对象的原型。这是每一个 JavaScript对象(除了 null )都具有的一个属性.

内部属性,是不能被直接访问的。所以为了方便查看一个对象的原型,Firefox和Chrome中提供了__proto__这个非标准(不是所有浏览器都支持)的访问器(ES5引入了标准对象原型访问器Object.getPrototype(object))。

function Person() {

}var person = new Person();console.log(person.__proto__) ;// Person {}// console.log(Object.getPrototypeOf(person)); // Person {}console.log(person.__proto__.__proto__); // Object {}

通过输出结果可以看到,Person {}作为一个原型对象,也有__proto__属性(对应原型的原型)。

console.log(Object.prototype.__proto__ === null); // true

null 表示“没有对象”,即该处不应该有值。
所以 Object.prototype.__proto__的值为 null 跟 Object.prototype 没有原型,其实表达了一个意思。

所以查找属性的时候查到 Object.prototype 就可以停止查找了。

prototype

在 JavaScript 中,每个函数都有一个 prototype 属性。当一个函数被用作构造函数来创建实例时,该函数的 prototype 属性值将被作为原型赋值给所有对象实例(也就是该实例的__proto__属性),即所有实例的原型引用的是函数的 prototype 属性。

注:prototype 属性是函数对象特有的。(函数才会有的属性)

function Person() {

}var person = new Person();console.log(Person.prototype); // Person {}console.log(person.__proto__ === Person.prototype) ;// true// console.log(Object.getPrototypeOf(person) === Person.prototype) // trueconsole.log(Person.prototype.__proto__) // Object {}// Person.prototype.__proto__ === Object.prototype // trueconsole.log(Object.prototype); // Object {}

当通过Person.prototype.__proto__语句获取实例 person 对象原型的原型时候,将得到Object {}对象,可以看到所有对象的原型都将追溯到Object {}对象

  • 查看函数对象 Function 的原型

function Person() {}console.log(Person.__proto__ === Function.prototype); // trueconsole.log(Person.constructor === Function); // trueconsole.log(Function.prototype.__proto__ === Object.prototype); // trueconsole.log(Function.prototype.constructor === Function); // true

在 JavaScript 中有个 Function 对象(类似Object),这个对象本身是个函数;所有的函数(包括Function,Object)的原型(__proto__)都是Function.prototype

Function 对象作为一个函数,就会有prototype属性,该属性将对应  function () {}对象。
Function 对象作为一个对象,就有__proto__属性,该属性对应"Function.prototype",也就是说,Function.__proto__ === Function.prototype
对于 Function 的原型对象Function.prototype,该原型对象的__proto__属性将对应Object {}

  • 如何理解原型:每一个JavaScript对象(null除外)在创建的时候就会与之关联另一个对象,这个对象就是我们所说的原型,每一个对象都会从原型"继承"属性。

上面说的都是通过构造函数创建对象,当使用对象字面量的形式创建对象时,该对象的原型就是Object.prototype

let obj = {};
obj.__proto__ === Object.prototype;

construcor

每个原型对象都有一个 constructor 属性指向关联的构造函数。

实例与原型(原型链的属性查找):当读取实例的属性时,如果找不到,就会查找该实例对象关联的原型中的属性,如果还查不到,就去找原型的原型,一直找到最顶层 Object 为止。如果仍然没有找到指定的属性,就会返回 undefined。

即当通过原型链查找一个属性的时候,首先查找的是对象本身的属性,如果找不到才会继续按照原型链进行查找。

function Person() {
}var person = new Person();console.log(Person === Person.prototype.constructor); // trueconsole.log(person.constructor == Person); // true

当获取 person.constructor 时,其实 person 中并没有 constructor 属性,当不能读取到constructor 属性时,会从 person 的原型也就是 Person.prototype 中读取。

构造函数 Person 利用其原型对象上的 constructor 引用了自身,当构造函数 Person 作为构造函数来创建对象时,原型上的 constructor 就被遗传到了新创建的实例对象上,从原型链角度讲,构造函数 Person 就是新对象的类型。这样做的意义是,让新对象在诞生以后,就具有可追溯的数据类型。

由此,可以通过constructor这个属性,来判断一个对象类型。尤其用来判断 js 内置对象的类型。

687

判断内置对象的类型


  1. null 和 undefined 是无效的对象,因此是不会有 constructor 存在的,这两种类型的数据需要通过其他方式来判断。

  2. 函数的 constructor 是不稳定的,这个主要体现在自定义对象上,当开发者重写 prototype 后,原有的 constructor 引用会丢失,constructor 会默认为 Object

function Person () {}
Person.prototype = {'name': 'xql'};var person = new Person();console.log(person.constructor === Person); // falseconsole.log(person.constructor === Object); // true

prototype 被重新赋值的是一个 { }, { } 是 new Object() 的字面量,因此 new Object() 会将 Object 原型上的 constructor 传递给 { },也就是 Object 本身。

通常,为了规范开发,在重写对象原型时一般都需要重新给 constructor 赋值,以保证对象实例的类型不被篡改。

hasOwnProperty()

function Person () {}var person = new Person();
person.hasOwnProperty('constructor'); // false

hasOwnProperty()Object.prototype的一个方法,该方法能判断一个对象是否包含自定义属性而不是原型链上的属性,因为hasOwnProperty()"是 JavaScript 中唯一一个处理属性但是不查找原型链的函数。

hasOwnProperty()还有一个重要的使用场景,就是用来遍历对象的属性。

function Person(name, age){    this.name = name;    this.age = age;
}

Person.prototype.getInfo = function(){    console.log(this.name + " is " + this.age + " years old");
};var person = new Person("Will", 28);for(var attr in person){    console.log(attr);
}// name// age// getInfofor(var attr in person){    if(person.hasOwnProperty(attr)){        console.log(attr);
    }
}// name// age

References

JavaScript深入之从原型到原型链
彻底理解JavaScript原型
判断JS数据类型的四种方法



作者:黎贝卡beka
链接:https://www.jianshu.com/p/d1c7325c7e9a


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP