文章目录
  1. 1. 首先说说new()到底做了什么.

首先说说new()到底做了什么.

1.创建一个新对象.
2.将构造函数的作用域付给新对象(因此this就指向了这个新对象).
3.执行构造函数的代码(为这个新对象添加属性).
4.返回新对象.(如果没有返回值或者函数有返回值,但是该返回值不是对象的话,则返回第一步建立的对象,如果函数没有返回值,且返回值是对象的话,则忽略第一步建立的对象,返回默认返回的对象.)

用栗子说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function Animal(name){
this.name = name;
}
Animal.color = "black";
Animal.prototype.say = function(){
console.log("I'm " + this.name);
};
var cat = new Animal("cat");

console.log(
cat.name, //cat
cat.color //undefined
);
cat.say(); //I'm cat

console.log(
Animal.name, //Animal
Animal.color //back
);
Animal.say(); //Animal.say is not a function

Animal 本身是一个普通函数,但当通过new来创建对象时,Animal就是构造函数。
JS引擎执行这句代码时,在内部做了很多工作,用伪代码模拟其工作流程如下:

1
2
3
4
5
6
7
8
9
10
new Animal("cat") = {

var obj = {};

obj.__proto__ = Animal.prototype;

var result = Animal.call(obj,"cat");

return typeof result === 'object'? result : obj;
}

(1)创建一个空对象obj;
(2)把obj的proto指向构造函数Animal的原型对象prototype,此时便建立了obj对象的原型链:obj->Animal.prototype->Object.prototype->null
(3)在obj对象的执行环境调用Animal 函数并传递参数“cat”。 相当于var result = obj.Animal(“cat”)。
(4)考察第3步返回的返回值,如果无返回值或者返回一个非对象值,则将obj返回作为新对象;否则会将返回值作为新对象返回。

理解了其运行机制以后,我们知道cat其实就是过程(4)的返回值,因此我们对cat对象的认知就多了一些:
cat的原型链是:cat->Animal.prototype->Object.prototype->null
cat上新增了一个属性:name
分析完了cat的产生过程,我们再看看输出结果:
cat.name -> 在过程(3)中,obj对象就产生了name属性。因此cat.name就是这里的obj.name

cat.color -> cat会先查找自身的color,没有找到便会沿着原型链查找,在上述例子中,我们仅在Animal对象上定义了color,并没有在其原型链上定义,因此找不到。

cat.say -> cat会先查找自身的say方法,没有找到便会沿着原型链查找,在上述例子中,我们在Animal的prototype上定义了say,因此在原型链上找到了say方法。
另外,在say方法中还访问this.name,这里的this指的是其调用者obj,因此输出的是obj.name的值。

对于Animal来说,它本身也是一个对象,因此,它在访问属性和方法时也遵守上述查找规则,所以:
Animal.color -> “black”
Animal.name -> “Animal” , Animal先查找自身的name,找到了name, 但这个name不是我们定义的name,而是函数对象内置的属性。

一般情况下,函数对象在产生时会内置name属性并将函数名作为赋值(仅函数对象)。
Animal.say -> Animal在自身没有找到say方法,也会沿着其原型链查找,话说Animal的原型链是什么呢?

从测试结果看:Animal的原型链是这样的:
Animal->Function.prototype->Object.prototype->null
因此Animal的原型链上没有定义say方法!

在Javascript中, 通过new可以产生原对象的一个实例对象,而这个实例对象继承了原对象的属性和方法。因此,new存在的意义在于它实现了Javascript中的继承,而不仅仅是实例化了一个对象!

再写个测试栗子

1
2
3
4
5
6
7
function Test() {    
  this.name = 'Test';
  return 'Test';
}

var fnT = Test(); //Test
var newT = new Test();//{}

我们可以在分析一下

1
var newT = new Test();

它干了什么

1
2
3
4
5
6
7
8
9
10
new Test() = {

var obj = {};

obj.__proto__ = Test.prototype;

var result = Test.call(obj);

return typeof result === 'object'? result : obj;
}

重要的是第三点
在obj环境中执行调用Test函数,用result变量承接Test函数的结果.显然这里是个字符串.
第四步:
返回的字符串’Test’不是一个’oobject’类型,则将obj作为返回值返回.

再写个测试栗子

1
2
3
4
5
6
function Test() {    
  this.name = 'Test';
  return function() { return true; }
}
var test1 = Test(); //function test(){}
var test2 = new Test(); // function (){}

test1 就单纯的是一个变量承接 一个函数.没什么好说的.

重点再来分析一一下test2.

1
2
3
4
5
6
7
8
9
10
new Test() = {

var obj = {};

obj.__proto__ = Test.prototype;

var result = Test.call(obj);

return typeof result === 'object'? result : obj;
}

第四步返回的是一个function (){} 是’object’类型.就直接返回result去承接这个变量.注意 不是obj,所以this.name = ‘Test’,是在obj这个对象里.

(Function Array RegExp 也算obj的一种)

文章目录
  1. 1. 首先说说new()到底做了什么.