JS小知识 new关键字都做了什么?

1,073 阅读4分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

10/15读红宝书后更新

image.png 这里说得很全面~(关键是很权威😂)

跟下文按照例子列出的步骤基本是完全一致(看得出来之前我看得几篇文章也都是受红宝书影响de~)

来看一个面向对象中的小问题

不知道大家有没有想过 在创建一个实例对象的时候 new关键字都起到了哪些作用嫩

在没有学习原型之前 我们可以这么给出定义——

  • 【1】创建一个 类(或者模拟类 比如说构造函数~)的实例对象

之前学Java面向对象的时候 并没有在这里想太多 就是知道 new一个对象嘛~创建出来的实例对象继承了父类的所有属性与方法 就这些🤔

那么在JavaScript中 情况有些不同

尤其是学过原型之后 我们知道 JS中的new关键字还背负着一些使命

这里涉及了原型、this指向、作用域、函数return的知识

举个例子来把内容串起来~

 function Person(name, age){
     this.name = name;
     this.age = age;
 }
 Person.prototype.getName = function(){
     console.log(this);//
     return this.name;// 通过this调用新创建的对象实例中的属性
 };
 ​
 var person = new Person("bill",21);
 console.log(person.name,person.age);// bill 21
 person.getName();//"bill"

上面那些代码中是看不出来new关键字做了什么的!

我们用伪代码模拟下上述过程的执行过程 也就是这一句

 var person = new Person("bill",21);

等同于下面内容

21/10/23 更新,第一版理解错了XD!这回完全正确,并且更全面了!😎

21/11/16 更新,第二版也有小错误XD!构造函数的返回值如果是对象类型,则创建实例对象时获得的是那个对象,而非创建的那个实例对象!😂

 new Person('bill',21) = {
     // 01 新建空对象实例
     var person = {};
     // 02 将构造函数的原型绑定到新创的对象实例上
     person.__proto__ = Person.prototype;
     // 03 调用构造函数并获得返回值res
     var res = Person.call(person, 'bill', 21);
     // 04 判断构造函数的返回值类型,如果res为对象类型,new Person的最终结果为res 而非我们想要的那个实例对象person!
     let isObject = typeof res === 'object' && res !== null;//判断res是否为对象
     // 额外注意 typeof null = object 
     let isFunction = typeof res === 'function';
     // 05 如果构造函数的返回值为对象类型
         //(比如{text: 'fake~'}),则调用new Person('bill', 21)会返回{text: 'fake~'}.
     // 如果返回值不是对象类型就返回之前新建的实例对象person
     return isObject || isFunction ? res : person;
 }

来拆分开看看~

  • 【1】创建了一个新的空对象 {}
 var person = {};
  • 【2】将新对象的 __proto__ 指向构造函数的 prototype 属性

    • 也就是设置这个对象原型指向构造函数
 person.__proto__ = Person.prototype;

这里还可以像下面一样写,效果相同的。

person.__proto__ = Object.create(Person.prototype);
Object.setPrototypeOf(person, Person.prototype);
  • 【3】将构造函数的作用域赋值给新对象(this指向新创建的对象实例person)

这里注意Person.call(person, args)会为这个新对象person添加属性(同时this会指向新创建的对象)

另外返回值res为构造函数的返回值(因为这个过程相当于调用构造函数~)

 var res = Person.call(person, 'bill', 21);
  • 【4】返回新对象(这里注意 如果构造函数中return一个对象 那么会返回return的内容 而不是创建的这个对象!!)
 return res;

截至此处 new关键字的工作就完成了

但是刚才涉及的知识需要原型链的知识作为前置知识 再看一下这条链 强化下记忆!

原型链必会概念
 // 要有顺着原型链找东西的技巧 
 // 甭管是 常规的 找方法、找属性
 // 还是面试中可能问的找构造函数 找Function Object的显式原型
 /*(比如写一个 Function.prototype.func = function(){...} 
  要知道这个func方法 哪些实例对象可以调用(顺着原型链的隐式原型那条路线要能抵达Function的显式原型 那就能用那上面的方法!) */
 var Foo = function(){...};
 var foo = new Foo();                       
 console.log(foo.__proto__.__proto__ === Object.prototype;)//true 

脑子里要有这幅图~

image.png

再看一张图——

可以看到实例对象 顺着原型链可以找到Object的原型对象

Object的原型对象上有很多定义好的方法~

另外Object的原型对象与Function的原型对象也有联系 即——

Function.prototype.__proto__ = Object.prototype

这个在面试题里面出现得比较多

Fn.__proto__ = Function.prototype;

Function.prototype.__proto__ = Object.prototype;

这样Fn(构造函数)就可以访问Object上定义的方法fn(Object.prototype.fn = function(){...})了!(借鉴于真实面试题

在这里插入图片描述