1、实例对象与New命令
(1)new命令的原理
若构造函数内部有 return 语句,并且 return 语句返回一个对象,new 命令会返回这个 return 语句,否则就会不管这个 return语句,返回 this 对象。
若return 语句返回的是跟 this 无关的对象,new 命令会返回这个新对象,而不是 this 对象。
若是内部没有 this 的普通构造函数使用 new 命令,则会返回一个空对象。
//例 1
var Vehical = function (){
this.price = 1000;
return 2000;
};
(new Vehical()) === 2000; //false
//例2
var Vehical = function(){
this.price = 1000;
return {price:2000;}
};
(new Vehical()).price ; //2000
//例3
function getMessage(){
return "This is a message";
}
var msg = new getMessage();
msg ; //{}
typeof msg ;//object
(2)this:简单地说, this 就是属性或方法 “当前”所在的对象。
(3)绑定 this 的方法
Function.prototype.call():参数可以指定函数内部 this 的指向(即函数执行时所在的作用域),然后在该作用域下调用该函数。该参数应为对象,若该参数是 null,undefined 或为空,则默认传入全局对象。若该参数为原始值,则该值会被转换成对象。
//例 1
var obj = {};
var f = function(){
return this;
};
f() === window //true
f.call(obj) === obj //true
//例 2
var n = 123;
var obj = {n:456};
var f = function(){
return this.n
};
f.call() //123
f.call(null) //123
f.call(undefined) //123
f.call(window) //123
f.cal(obj) //456
Function.prototype.apply():与 call()类似,参数也是指定函数运行时 this 的作用域,但是它的第一个参数是 this 要指向的对象,第二个参数是数组。
apply()最重要的作用是将对象转换为数组,对象须具有 length 属性
Array.prototype.slice.apply({0:1,length:1}); //[1]
Array.prototype.slice.apply({0:1}); //[]
Array.prototype.slice.apply({0:1,length:2}); //[1,undefined]
Array.prototype.slice.apply({length:1}); //[undefined]
Function.prototype.bind():用于将函数体内的 this 绑定到某个对象,然后返回一个新的函数。
var d = new Date();
d.getTime(); // 1481869925657
var print = d.getTime();
print(); //Uncaught TypeError: this is not a Date object.
若改为 var print = d.getTime.bind(d);
print(); // 1481869925657
2.原型对象:定义所有实例对象共享的属性和方法。
对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型。原型对象的属性不是实例对象自身的属性,只要修改原型对象,变动就会立刻体现在所有实例对象上。
function Animal(name){
this.name = name;
}
Animal.prototype.color = "black";
var cat = new Animal("小猫");
var dog = new Animal("小狗");
cat.color //"black"
dog.color //"black"
若是实例对象自身就有某个属性或方法,它就不会再去原型对象再找这个属性或方法了。
Animal.prototype.color = "yellow";
cat.color = "white";
cat.color //"white"
dog.color //"yellow"
3.constructor属性:
(1)可以得知某个实例对象,到底是哪一个构造器产生的。
function F (){};
var f = new F();
f.constructor === F; //true
f.constructor === RegExp; //false
(2)有了 constructor 属性,就可以从一个实例对象新建另一个实例。
//1
function Constr(){};
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true
//2
Constr.prototype.createCopy = function(){
return new this.constrcutor();
};
//createCopy 方法调用构造函数,新建另一个实例。
(3)constructor 表示原型对象与构造函数之间的关联关系,若修改原型对象,则同时修改 constructor 属性,不然会报错。
function Person(name){
this.name = name;
}
Person.prototype.constructor === "Person" //true
Person.prototype ={
methon:function() {}
};
Person.prototype.constructor ==="Person" //false
Person.prototype.constructor === "Object" //true
共有两种修改方法
//方法1
C.prototype = {
constructor:C,
method:function(){}
};
//方法2 方法2 更好
C.prototype.method = function(){};
4.instanceof运算符:返回一个布尔值,表示对象是否为某个构造函数的实例(原理是检查右边的实例对象,是否在左边对象的原型链上)。instanceof 只适用于对象,不适用于原始类型的值。
var v = new Vehical();
v instanceof Vehical; //true
//等同于
Vehical.prototype.isPrototypeOf(v); //true
(1)由于 instanceof 检查整个原型链,因此同一个实例对象可能会对多个构造函数都返回 true。
var d = new Date();
d instanceof Date; //true
d instanceof Object;//true
(2)由于除了 null 之外,任意对象都是 Object 的实例,所以用 instanceof可以判断一个值是否为非 null 对象。
var obj = {foo:123};
obj instanceof Object; //true
null instanceof Object; //false
(3)有一种特殊情况,当左边对象的原型链上只有 null 时,instanceof 判断就会失真。
var obj = Object.create(null);
typeof obj ; //Object
Object.create(null) instanceof Object //false
5.构造函数的继承
第一步:在子类的构造函数中,调用父类的构造函数
function Sub(){
Super.call(this);
this.prop = value;
}
以上代码中,Sub是子类构造函数,this 是子类的实例,在实例上调用父类的构造函数 Super,就会让子类实例具有父类实例的属性。
第二步:让子类的原型指向父类的原型,这样子类就可以继承父类原型。
Sub.prototype = Object.create(Super.prototype);
Sub.prototype.constructor = Sub;
Sub.prototype.method = "......";
另一种方法如下,但是这样子类会有父类实例的方法,所以这种用法我们不推荐。
Sub.prototype = new Super();
有时需要继承父类构造器里的单个方法,则
ClassB.prototype.method1 = {
ClassA.prototype.method1.call(this);
...
};
6.多重继承:JS里边不支持多重继承,但是可以通过别的方法使其具有多重继承的功能
function M1(){
this.hello = "hello";
}
function M2(){
this.world = "world";
}
function S(){
M1.call(S);
M2.call(S);
}
S.prototype = Object.create(M1);//继承 M1
Object.assign(S.prototype,M2.prototype);//继承链上加上 M2
S.prototype.constructor = S; //指定构造函数
var s = new S();
s.hello //"hello"
s.world //"world"
7.Object对象
(1)获取对象原型的三种方法
方法一:obj._proto_ ,只有浏览器才需要部署,其他情况下不需要
方法二:obj.prototype.constructor,在手动改变原型数据时,可能会失效
方法三:Object.getPrototypeOf(obj) ,这种方法最好
(2)hasOwnProperty() ,用于判断某个对象属性是定义在对象自身,还是定义在原型链上。还是此方法是 JS 中唯一一个处理原型对象属性时,不需要遍历链的方法