小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
10/15读红宝书后更新
这里说得很全面~(关键是很权威😂)
跟下文按照例子列出的步骤基本是完全一致(看得出来之前我看得几篇文章也都是受红宝书影响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
脑子里要有这幅图~
再看一张图——
可以看到实例对象 顺着原型链可以找到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(){...})了!(借鉴于真实面试题)