

Object类型是目前JavaScript中使用最多的一个类型,目前大家使用的大部分引用数据类型都是Object类型,Object类型的使用频率高是因为其对于数据存储和传输是非常理想的选择。由于引用数据类型的实例都需要通过new操作符来生成,因此我们需要了解new操作符的相关知识。
new操作符在执行过程中会改变this的指向,所以了解new操作符之前,我们先了解一下this的用法。
function Person(name, age) {
this.name = name;
this.age = age;
}
console.log(new Person('miaomiao', 18));//Person{name:"qhhh",age:18}
输出的结果包含了name和age的信息,事实上我们并未通过return返回任何值,为什么输出的信息中会包含name和age属性呢?其中起作用的就是this这个关键字了。
我们通过以下代码输出this,看看this的具体内容:
function Person(name,age){
console.log(this);
this.name = name;
this.age = age;
}
new Person('qhhh',18);
我们可以发现this的实际值是Person的空对象,后两句就相当于给Person对象添加name和age属性,结果 真的是这样吗?不如我们改写一下Person函数。
function Person(name,age){
var Person = {};
Person.name = name;
Person.age = age;
}
console.log(new Person('qhhh',18));
我们可以发现输出的结果中并没有包含name和age属性,这是为什么呢?
因为在JavaScript中,如果函数没有return值,则默认return this。而上面代码中的this实际是一个Person空对象,name和age属性知识被添加到了临时变量Person中,为了能让输出结果包含name和age属 性,我们将临时变量Person进行return就行了。
function Person(name,age){
var Person = {};
Person.name = name;
Person.age = age;
return Person;
}
console.log(new Person('qhhh',18));
最后的返回值中包含了name和age属性,通过以上的分析,我们了解了构造函数中this的用法,那么它与new操作符之间有什么关系呢?
我们先来看看下面这行简单的代码,该代码的作用是通过new操作符生成一个Person对象的实例。
var Person = new Person();
从表面上看这行代码的主要作用是创建一个Person对象的实例,并将这个实例值赋予person变量,person变量就会包含Person对象的属性和函数。
其实使用new操作符做了三件事情,如下代码所示:
第一行:创建一个空对象。
var person = {};
person.__proto__ = Person.prototype;
Person.call(person);
第二行:将空对象的 __proto__ 属性指向Person对象的prototype属性。
第三行:将Person()函数中的this指向person变量。
于是person变量就是Person对象的一个实例。
我们自定义一个类似new功能的函数,来具体讲解上面的三行代码。
function Person(name,age){
this.name = name;
this.age = age;
}
function New(){
var obj = {};
var res = Person.apply(obj,arguments);
return typeof res === 'object' ? res : obj;
}
console.log(New('qhhh',18));
返回的结果中包含name和age属性,这就证明了new运算符对this指向的改变,Person.apply(obj.arguments)调用后Person对象中的this就指向了obj对象,这样obj对象就具有了name和age 属性。
因此,不仅要关注new操作符函数本身,也要关注它的原型属性。
我们对上面的代码进行改动,在Person对象的原型链上增加一个sayHi()函数,然后通过New()函数返回的对象,去调用sayHi()函数,看看执行情况如何。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function(){
console.log('Hi');
}
function New(){
var obj = {};
var res = Person.apply(obj,arguments);
return typeof res === 'object' ? res : obj;
}
console.log(New('qhhh',18));
console.log(New('qhhh',18).sayHi());
我们发现执行报错了,New()函数返回的对象并没有调用sayHi()函数,这是因为sayHi()函数是属于Person原型的函数,只有Person原型链上的对象才能继承sayHi()函数,那么我们应该怎样做呢?
这里需要用到的就是 __proto__ 属性,实例的 __proto__ 属性指向的是创建实例对象时,对应的 函数的原型。设置obj对象的 __proto__ 值为Person对象的prototype属性,那么obj对象就继承了Person原型 上的sayHi()函数,这样就可以调用sayHi()函数了。
function Person(name,age){
this.name = name;
this.age = age;
}
Person.prototype.sayHi = function(){
console.log('Hi');
}
function New(){
var obj = {};
obj.__proto__ = Person.prototype; //核心代码,用于继承。
var res = Person.apply(obj,arguments);
return typeof res === 'object' ? res : obj; }// console.log(New('qhhh',18));
console.log(New('qhhh',18).sayHi());
The very next time I read a blog, Hopefully it wont disappoint me just as much as this particular one. I mean, I know it was my choice to read, however I really thought youd have something interesting to say. All I hear is a bunch of crying about something that you can fix if you werent too busy seeking attention.