构造函数1_模拟new

"Hello World, Hello Blog"

Posted by wudimingwo on December 15, 2018

1,构造函数内部原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
前提必须要加 new,以下三步都是隐式的:
1.在函数体最前面隐式的加上 var this = {} 空对象
2.执行 this.xxx = xxx;
3.隐式的返回 return this

模拟写以下 new

 Person.prototype.name = 'mike';
      function Person (age) {
      	this.age = age;
      }
      
      var person = new(Person)(18);
      
      console.log(person.age);
      console.log(person.name);
      
      var newNew = function (fn) {
      	var self = Object.create(fn.prototype);
      	var fun = function () {
      		var args = arguments;
      		fn.apply(self,args);
      		return self;
      	}
      	return fun;
      }
      var persona= newNew(Person)(18);
      
      console.log(persona.age);
      console.log(persona.name);

看似我们模拟的这个new是成功的.
也有助于理解我们日后使用new以及this指向问题.
但按照我模拟写的newNew 无论我在Person(){}里return 什么东西,
最终return 的都应该是 self

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Person.prototype.name = 'mike';
      function Person (age) {
      	this.age = age;
      	var fun = function () {console.log(12346);};
      	return 5 当return 5的时候确实没有任何作用
      	return fun 当return一个引用值的时候,就会取代self
        而用我自己写的newNew的时候,则即使是引用值也不会产生作用.
        这表明:我模拟的new还是跟原生new是不一样的.
        其次,我不明白这样设置有什么用意.
        因为返回的东西似乎也并不能继承原型链.
      }
      
      var person = new(Person)(18);
      
      console.log(person.age);
      console.log(person.name);
      
      var newNew = function (fn) {
      	var self = Object.create(fn.prototype);
      	var fun = function () {
      		var args = arguments;
      		fn.apply(self,args);
      		return self;
      	}
      	return fun;
      }
      var persona= newNew(Person)(18);
      
      console.log(persona.age);
      console.log(persona.name);

网上有涉及相同内容的: https://blog.csdn.net/SpicyBoiledFish/article/details/70858565


我看了这篇文章,然我脑子又变得复杂了 你不知道的javascript之Object.create 和new区别 https://blog.csdn.net/blueblueskyhua/article/details/73135938

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
刚开始,我看到博主写一个
Base.protytpe.name = 'mike'
function Base () {}
var obj = Object.create(Base);
这种语句,我就感觉这人是不是有毛病, 因为我的常识告诉我,不能放函数,应该放对象.
应该
var obj = Object.create(Base.prototype);

后来我细思量,觉得前一种也能间接继承,
obj.prototype.name // 返回mike
这是因为Base这个函数是一种特殊的对象,prototype应该是Base的一个属性.
obj继承了Base, 那么obj就应该能访问Base上的任何属性,以及Function.prototype上的任何属性
所以obj.继承Base,也能间接调用Base.prototype上的属性和方法.
当然,this默认不指向obj.

其实感觉也没什么用处.
不过一个对象的原型,可以是一个函数,一个函数可以成为另一个对象的原型,
这个事实本身还是很开脑洞的.


第二个让我脑子复杂的是模拟Object.create()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
在上面,我是用Object.create()来模拟的new
而在这篇博客里面,有写到用 new模拟Object.create.

Object.create = function (obj) {
  function F () {};
  F.prototype = obj;
  return new F();
}
咦? 这样确实有助于我们了解 create, 但变成是鸡生蛋还是蛋生鸡的问题了.
我们总不能 用new 和 create相互模拟吧?

而实际上 new可以不用 create模拟

var newNew = function (fn) {
    var obj = {};
    obj.__proto__ = F.prototype;
     function F () {
      fn.apply(obj,arguments);
      return obj;
}
  return F;
} 

这虽然看起来没用new 实际上 {} 是 new Object() 来的吧?

紧接着后面又出现一个让我稍微混乱的东西 博主 分析 instanceof 和 isPrototypeOf

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
让我混乱的就是: 博主用 instanceof 模拟 isPrototypeOf
function isRelatedTo(o1,o2){
    function F(){}
    F.prototype = o2;
    return o1 instanceof F;
}

这我一看,第一眼我是觉得这个不靠谱的啊!
因为o1的原型链上不可能有F 的啊!!这F是这个isRelatedTo执行的时候才定义的好嘛?!

测试结果让我混乱了,确实跟isPrototypeOf的效果是一样的.
后来经过另外一些简单测试,得出一个结论,
这个instanceof F中的F的原型只要在某个实例对象的原型链上,
那么这个 instanceof 就都会返回true.......

比如说
function Person0 () {this.name = 0}
var person = new Person0();
function Person1() {this.name = 1}
function Person2() {this.name = 2}
function Person3() {this.name = 3}
Person1.prototype = Person2.prototype = Person3.prototype = Person0.prototype;
请问
person instanceof Person1 /2/3 返回什么?   返回true!
如果直接
Person0.prototype = Person1.prototype
person instanceof Person0  返回什么? 返回false..

最后的结论是, instanceof  是靠不住的, 可能 isPropertyOf 靠得住吧.
大家应该还记得 constructor 是靠不住的吧, 现在instanceof 也阵亡了.

============================= 虽然上面写得逻辑不是很清楚, 但足以表明我当时学的还是挺认真的, 挺有专研精神的

好了,我们补一下, 之前的模拟new 是有个缺陷的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
            function myNew (fun) {
            	return function () {
            	  var self = Object.create(fun.prototype);
            		fun.apply(self,arguments)
            		return self;
            	}
            }
这样 虽然能够返回 this
也能正常继承.
但如果构造函数内部返回一个引用值时,就无法模拟了

所以可以这样

            function myNew (fun) {
            	return function () {
            	  var self = Object.create(fun.prototype);
            		var result = fun.apply(self,arguments)
            		if (typeof result == "object") {// 判断返回值的类型
            			return result
            		}
            		return self;
            	}
            }