JS-原型和原型链、new一个新对象

327 阅读4分钟

在讲原型和原型链之前,我们先来了解一下构造函数。

构造函数

构造函数本身就是一个函数,不过为了规范一般将其函数名的首字母大写。

构造函数和普通函数的区别在于,使用 new 生成实例的函数就是构造函数,直接调用的就是普通函数。

function Person(name) {
  this.name = name;
}
let person1 = new Person('xmm');
console.log('姓名:', person1.name);
//姓名: xmm

在上面的代码中,Person就是构造函数,使用new创建了一个实例对象person1

代码

接下来我会根据一段代码和相应的图解来讲述原型prototype和原型链__proto__的的区别和联系。

//构造函数 Person
function Person(name) {
  this.name = name;
}
Person.sex = 'girl';
Person.prototype.age = 18 ;
console.log('Person.sex ',Person.sex);         //Person.sex  girl

// 构造函数的实例
let person1 = new Person('gxm');
let person2 = new Person('xmm');

console.log('person1.name:', person1.name);  //person1.name:gxm
console.log('person2.name:', person2.name);  //person2.name:xmm

//修改和自定义属性
person1.age = 20;
person2.loveAction = '指尖的跳跃';
console.log('person1.age:', person1.age);    //person1.age:20
console.log('person2.age:', person2.age);    //person2.age:18
console.log('person2.loveAction:', person2.loveAction);//person2.loveAction: 指尖的跳跃

console.log('person1.sex', person1.sex);      //person1.sex undefined
console.log('person2.sex', person2.sex);      //person1.sex undefined

console.log(person1.__proto__ === Person.prototype);  // true
console.log(person1.constructor === Person);          // true
console.log(Person.prototype.constructor === Person); // true

图解:

原型 prototype

构造函数的原型prototype属性是一个指针,指向的是原型对象,关系如下:

每个函数都会有一个prototype属性,这个属性是一个指针,指向原型对象(如图中的Person .prototype),这个对象正是调用该构造函数而创建的实例的原型,也就是这个例子中的 person1person2 的原型。

记住只有函数才有,并且通过bind()绑定的也没有。

原型对象的好处是可以让所有对象实例共享它所包含的属性和方法。

引申:constuctor和原型对象的关系

现在理解原型对象(Person.prototype)下constructor属性

这个constuctor属性其实就是将原型对象指向关联的构造函数。上述代码中的这两句输出语句可以说明。

console.log(person1.constructor === Person);          // true
console.log(Person.prototype.constructor === Person); // true

实例 person1person2可以通过__proto__来访问构造函数的原型对象。就是我们接下来要讲的__proto__属性。

原型链 __proto__

其实每个JS对象都有__ proto __属性,这个属性指向了原型。这个属性在现在来说已经不推荐直接去使用了,这只是浏览器在早期为了让我们访问到内部属性[[prototype]]来实现的一个东西。

person1person2实例对象下面有一个[[prototype]]属性,其实没有标准的方式可以访问它,但是主流浏览器上在每个对象上 (null除外) 都支持一个属性,那就是__ proto __,这个属性会指向该对象的原型。

所以总结可得__ proto __就是用来将 实例对象该实例对象的原型相连

new 一个新对象,这个过程发生了什么

  1. 创建一个新对象
  2. 原型链继承
  3. 将构造函数的this指向这个新对象 – call,apply皆可
  4. 返回新对象
function Person(name, age) {
    this.name = name;
    this.age = age;
}
console.log(new Person('crystal', 24));
//在这里表示一下new一个新对象的过程
function createPerson(name, age) {
    // 1.生成一个新的对象
    var obj = Object.create();
    
    // 2.原型链继承,一旦实例化,实例应该拥有原来的函数的原型属性
    obj.__proto__ = Person.prototype;
    
    // 3.将Person中的this指向obj
    let res = Person.apply(obj, arguments);
   
    // 4.返回在这个res对象
    return res instanceOf Object ? res : obj;
}
new Person('crystal', 24) = createPerson('crystal', 24);

优化:

function _new(fn,...arg) {
    if (typeof fn !== 'function'){
        throw TypeError('the first param must be a function')
    }
    let obj = Object.create(fn.prototype);
    let res = fn.call(obj, ...arg);
    let resIsObj = typeof res === 'object' && res !== null;
    let resIsFun = typeof res === 'function';
    if (resIsObj || resIsFun){
        return res
    }
    return obj;
}

综上所述:

prototype是构造函数访问原型对象,_ proto _是对象实例访问原型对象。

补充:

  • Object 是所有对象的爸爸,所有对象都可以通过 __proto__ 找到Object.prototype,在通过Object.prototype.constructor找到它
  • Function 是所有函数的爸爸,所有函数都可以通过 __proto__ 找到Function.prototype,在通过Function.prototype.constructor找到它
  • 函数的 prototype 是一个对象
  • 对象的__proto__属性指向原型,__proto__将对象和原型连接起来组成了原型链

image.png

番外:

理解一个知识:

  1. Function.prototype.__proto__ == Object.prototype;
  2. Function.__proto__==Object.__proto__;

这就是为什么:

Function instanceof Object // ->true
Object instanceof Function // ->true

这里来解释一下:

  • 先来说说为什么Object instanceof Function的结果为ture,即Function.prototypeObject的原型链上

    Function这个内置函数的Function.prototype是一个函数a,因为函数同时也是对象,因此这个函数a也定义了applycallbind等属性(或者说方法)。而Object的委托目标Object.__proto__正是这个函数a,因此Object instanceof Function的结果为ture

  • 再来说说为什么Object.prototypeFunction的原型链上,即Function instanceof Objectture

    Object这个内置函数的Object.prototype是一个对象b,很多我们经常用到的属性(或者说方法)如:toStringvalueOfhasOwnPropertyisPrototypeOf就是定义在对象b上的。从图上可以看到,Function的委托目标竟然也是函数aFunction.prototypeFunction.__proto__都指向函数a),而函数a的委托目标正是对象b,因此Function instanceof Objectture

番外参考的是:blog.csdn.net/haishangfei…