一、媒介

引见组织函数,原型,原型链。好比说常常会被问道:symbol是不是是组织函数;constructor属性是不是只读;prototype、[[Prototype]]和__proto__的区分;甚么是原型链?等等题目

 

二、组织函数

1、甚么组织函数

组织函数就是经由过程new关键词天生实例的函数。

js的组织函数和其他言语不一样,一样平常范例都是首字母大写。

起首我们来看一下这个栗子:

// saucxs function Parent(age) { this.age = age; } var p = new Parent(30); console.log(p); //见下图 console.log(p.constructor); // ƒ Parent(age){this.age = age;} p.constructor === Parent; // true p.constructor === Object; // false

这就是一个典范的组织函数,组织函数自身也是个函数,与一般区分不大,重要区分就是:组织函数运用new天生实例,直接挪用就是一般函数。

 

2、constructor属性

返回建立实例对象的Object组织函数的援用。此属性的值对函数自身的援用,而不是一个包罗函数称号的字符串。

一切对象都邑从它的原型上继续一个constructor属性

var o = {}; o.constructor === Object; // true var o = new Object; o.constructor === Object; // true var a = []; a.constructor === Array; // true var a = new Array; a.constructor === Array // true var n = new Number(3); n.constructor === Number; // true

那末一般函数建立的实例有无constructor属性呢?

// saucxs // 一般函数 function parent2(age) { this.age = age; } var p2 = parent2(50); console.log(p2); // undefined // 一般函数 function parent3(age) { return { age: age } } var p3 = parent3(50); console.log(p3.constructor); //ƒ Object() { [native code] } p3.constructor === parent3; // false p3.constructor === Object; // true

上面代码申明:

(1)一般函数在内部有return操纵的就有constructor属性,没有return的没有constructor属性;

(2)有constructor属性的一般函数的constructor属性值不是一般函数自身,是Object。

 

3、symbol是组织函数吗?

MDN 是如许引见 `Symbol` 的

The `Symbol()` function returns a value of type **symbol**, has static properties that expose several members of built-in objects, has static methods that expose the global symbol registry, and resembles a built-in object class but is incomplete as a constructor because it does not support the syntax "`new Symbol()`".

Symbol是基础数据范例,作为组织函数它不完全,由于不支撑语法new Symbol(),若是要天生实例直接运用Symbol()就能够的。

// saucxs new Symbol(123); // Symbol is not a constructor Symbol(123); // Symbol(123)

虽然Symbol是基础数据范例,然则Symbol(1234)实例能够猎取constructor属性值。

// saucxs var sym = Symbol(123); console.log( sym ); // Symbol(123) console.log( sym.constructor ); // ƒ Symbol() { [native code] } sym.constructor === Symbol; //true sym.constructor === Object; //false

这里的constructor属性来自那里?实际上是Symbol原型上的,默以为Symbol函数。

 

4、constructor的值是只读的吗?

回覆:若是是援用范例的constructor属性值是能够修改的,若是是基础范例的就是只读的。

援用范例的状况,修改这个很好明白,好比原型链继续的计划中,就是对constructor从新赋值的修改。

// saucxs function Foo() { this.value = 42; } Foo.prototype = { method: function() {} }; function Bar() {} // 设置 Bar 的 prototype 属性为 Foo 的实例对象 Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; Bar.prototype.constructor === Object; //true
// 修改 Bar.prototype.constructor 为 Bar 自身 Bar.prototype.constructor = Bar; var test = new Bar() // 建立 Bar 的一个新实例 console.log(test);

 

关于基础范例来说是只读的,好比:1, "saucxs", true, Symbol, null, undefined。null和undefined也是没有constructor属性的。

// saucxs function Type() { }; var types = [1, "muyiy", true, Symbol(123)]; for(var i = 0; i < types.length; i++) { types[i].constructor = Type; types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ]; }; console.log( types.join("\n") ); // function Number() { [native code] },false,1 // function String() { [native code] },false,muyiy // function Boolean() { [native code] },false,true // function Symbol() { [native code] },false,Symbol(123)

为何会如许?由于建立他们的是只读的原生组织函数(native constructors),这个栗子申明依靠一个对象的constructor属性实在不平安。

 

三、原型

3.1 prototype属性

每一个对象都具有一个原型对象,对象以其原型为模板,从原型集成要领和属性,这些属相和要领都在对象的组织器函数的prototype属性上,而不是对象实例自身上。

上图发明:

1、Parent对象有一个原型对象Parent.prototype,原型对象上有两个属性,分别为:constructor和__proto__,个中__proto__已被弃用。

2、组织函数Parent有一个指向原型的指针constructor;原型Parent.prototype有一个指向组织函数的指针Parent.prototype.constrcutor,实在就是一个轮回援用。

 

3.2 __proto__属性

上图中能够看到Parent原型(Parent.prototype)上有一个__proto__属性,这是一个接见器属性(即getter函数和setter函数)。作用:经由过程__proto__能够接见到对象的内部[[Prototype]](一个对象或许null)

`__proto__` 发音 dunder proto,最早被 Firefox运用,厥后在 ES6 被列为 Javascript 的规范内建属性。

`[[Prototype]]` 是对象的一个内部属性,外部代码没法直接接见。

// saucxs function Parent(){}; var p = new Parent(); console.log(p); console.log(Parent.prototype);

1、p.__proto__猎取的是对象的原型,__proto__是每一个实例上都有的属性

2、prototype是组织函数的属性;

3、p.__proto__和Parent.prototype指向同一个对象。

// saucxs function Parent() {} var p = new Parent(); p.__proto__ === Parent.prototype // true

以是组织函数Parent,Parent.prototype和p之间的干系,以下图所示:

 

注重1:`__proto__` 属性在 `ES6` 时才被规范化

以确保 Web 浏览器的兼容性,然则不引荐运用,除规范化的缘由以外另有机能题目。为了更好的支撑,引荐运用 `Object.getPrototypeOf()`。

若是要读取或修改对象的 `[[Prototype]]` 属性,发起运用以下计划,然则此时设置对象的 `[[Prototype]]` 依旧是一个迟缓的操纵,若是机能是一个题目,就要制止这类操纵。

若是要建立一个新对象,同时继续另一个对象的 `[[Prototype]]` ,引荐运用 `Object.create()`。

// saucxs function Parent() { age: 50 }; var p = new Parent(); var child = Object.create(p);

这里 `child` 是一个新的空对象,有一个指向对象 p 的指针 `__proto__`。

 

四、原型链

每一个对象具有一个原型对象,经由过程__proto__指针指向上一个原型,并从中继续要领和属性,同时原型对象也能够具有原型,如许一层层的,终究指向null。这类干系成为原型链(prototype chain),作用:经由过程原型链一个对象会具有界说在其他对象中的属性和要领

// saucxs function Parent(age) { this.age = age; } var p = new Parent(50); p.constructor === Parent; // true

p.constructor指向Parent,那末是不是是意味着p实例化存在constructor属性呢?实在不存在,打印一下p:

有图能够晓得,实例化对象p自身没有constructor属性,是经由过程原型链向上查找__proto__,终究找到constructor属性,该属性指向Parent

// saucxs function Parent(age) { this.age = age; } var p = new Parent(50); p; // Parent {age: 50} p.__proto__ === Parent.prototype; // true p.__proto__.__proto__ === Object.prototype; // true p.__proto__.__proto__.__proto__ === null; // true

下图展现原型链运行机制。

 

五、总结

1、Symbol是基础数据范例,作为组织函数实在不完全,由于不支撑语法new Symbol(),然则原型上具有constructor属性,即Symbol.prototype.constructor。

2、援用范例constructor属性值是能够修改的,然则关于基础范例的是只读的,固然null和undefined没有constructor属性。

3、__proto__是每一个实例上都有的属性,prototype是组织函数的属性,这两个不一样,然则p.__proto__和Parent.prototype是指向同一个对象。

4、__proto__属性在ES6时被规范化,然则由于机能题目实在不引荐运用,引荐运用Object.getPropertyOf()。

5、每一个对象具有一个原型对象,经由过程__ptoto_指针指向上一个原型,并从中继续要领和属性,同时原型对象也能够具有原型,如许一层已成的,终究指向null,这就是原型链。

 

六、参考

1、原型对象

2、Objcet.prototype.constructor

3、Object.prototype.__proto__

4、Symbol

5、原型

 

文章首发地点(sau交流学习社区)

 

Last modification:March 25, 2020
如果觉得我的文章对你有用,请随意赞赏