深入理解原型、原型链

JavaScript构造函数与原型链
前面的话

学前端,在JavaScript上面花再多的时间都不为过。 这篇文章将介绍原型、原型链

什么是构造函数

构造函数与普通函数的区别:

  • 首写字母大写
  • 调用方式:使用new操作符调用
function Person(name, age) {
    this.name = name;
    this.age = age;
}
var p = new Person('wan', 20);
Symbol属于构造函数吗?

Symbol是es6新增的一种基本数据类型,但它不是完整的构造函数,因为它不支持new操作符,Chrome认为其不是构造函数,如果想生成实例,直接使用Symbol()来生成。

var x = new Symbol(123); //  Uncaught TypeError: Symbol is not a constructor
var y = Symbol(123);
constructor属性

每个函数的实例都有constructor属性,它返回的是创建实例对象的构造函数(是构造函数本身的引用,而不是函数名称的字符串)。

 function Person(name, age) {
    this.name = name;
    this.age = age;
}
var p = new Person('wan', 20);
console.log(p.constructor);
console.log(p.constructor == Person);

在这里插入图片描述
普通函数的实例对象也有constructor属性。大部分对象都具有这个属性。(Object.create(null)创建的实例对象没有)

 var a = Object.create(null);
     console.log(a.constructor);
     

参数为null的对象没有constructor属性。下面为讲到这方法
在这里插入图片描述
普通函数的实例也有constructor属性:

   function person() {
        return {
            age: 20
        }
    }
    var a = person();
    console.log(a.constructor);

在这里插入图片描述

基本数据类型:比如数字、字符串、布尔值(true/false)、Symbol()实例都具有constructor属性,null与undefined没有

// 数字 
console.log((1).constructor);

// 字符串

console.log('123'.constructor);

// 布尔值

console.log((true).constructor);

// Symbol(123)实例

console.log(Symbol(123).constructor);

在这里插入图片描述
那么这些constructor属性来自哪呢?例如(1).constructor是来自Number原型上的,即Number.prototype.constructor. 其他4个也是如此。

constructor属性是否只可读?

constructor属性对象引用类型的对象是可以修改的,但对于基本数据类型只是可读的

[引用类型]

  function Bar(){}
    function Foo(name) {
        this.name = name;
    }
    var f = new Foo('wan');
    console.log(f.constructor);
    f.constructor = Bar;
    console.log(f.constructor);

在这里插入图片描述
[基本的包装类型也是可以修改的]

var X = new Number(1);
console.log(X.constructor);
X.constructor = Bar;
console.log(X.constructor);

在这里插入图片描述

[基本数据类型只读]

console.log((1).constructor);
(1).constructor = Bar;
console.log((1).constructor);

在这里插入图片描述
同理,对于其他基本数据类型也是只可读

prototype属性

无论什么时候,只要创建一个新的函数,就会为该函数创建一个prototype属性,每一个函数都有一个prototype属性,这个属性是一个指针,指向一个对象,这个对象就是原型对象。原型对象的用途是:包含可以由特定类型的所有实例共享的属性和方法。

function Person1(name) {
   this.name = name;
}

var K = new Person1();

console.log(Person1.prototype);
console.log(Person1.prototype.constructor == Person1);

在这里插入图片描述
[普通函数]

function person1(name) {
    return {
        name:name
    }
}
var k = person();

console.log(person1.prototype);
console.log(Person1.prototype.constructor == Person1);

我们可以看到函数的prototype属性指向的是一个对象,并且该对象有两个属性:constructor属性__ proto__属性,其中 __ proto__ 已被弃用。constructor属性指向的是调用prototype属性的函数。

构造函数Person1有一个指向原型对象指针(prototype属性),Person1.prototype原型对象有一个指向构造函数的指针(constructor属性)
在这里插入图片描述

__ proto__

当调用构造函数创建一个实例时,该实例的内部将包含一个指针(内部属性),指向构造函数的原型对象,ECMA5管这个指针叫[[prototype]],但是外部的代码无法访问。但Firefox、Safari、Chrome在每个对象上都支持属性__ proto__.

给上例添加两行代码:

     console.log(K);
     console.log(K.__proto__ === Person1.prototype);

在这里插入图片描述

每个对象都有一个__proto__属性,上例中返回的K实例中有一个__proto__属性,它指向的也是一个对象,与Person1.prototype指向的对象一样。

这里用 K.proto 获取对象的原型,prototype 是构造函数的属性,这两个并不一样,但 K.proto 和 Person1.prototype 指向同一个对象。

Object.create()

另一种创建构造函数实例的方法,它既可以创建一个构造函数实例,并且可以传入参数,这个参数要么是对象,要么为null

function Person2(age) {
    this.age = age
}
var N = new Person2(20);
var n = Object.create(N);
console.log(n.__proto__); 

在这里插入图片描述
如果参数是null,那么对象n将是一个空对象,并且这个对象将没有原型

var g = Object.create(null);
console.log(g.__proto__);

在这里插入图片描述

原型链

每个对象都有一个原型,通过__proto__指针指向上一个原型,一层一层到Object.prototype ,最终到null。这种关系被称为原型链 (prototype chain).

console.log(N.__proto__ === Person2.prototype);
console.log(N.__proto__.__proto__ === Object.prototype);
console.log(N.__proto__.__proto__.__proto__ === null);

在这里插入图片描述
关系图:在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

crazy的蓝色梦想

如果对你有帮助,就鼓励我一下吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值