面向对象编程

1.new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的。

var v = new Vehicle();
var v = new Vehicle;
一个很自然的问题是,如果忘了使用new命令,直接调用构造函数会发生什么事?这种情况下,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象。
2.

使用new命令时,它后面的函数调用就不是正常的调用,而是依次执行下面的步骤。

创建一个空对象,作为将要返回的对象实例
将这个空对象的原型,指向构造函数的prototype属性
将这个空对象赋值给函数内部的this关键字
开始执行构造函数内部的代码
也就是说,构造函数内部,this指的是一个新生成的空对象,所有针对this的操作,都会发生在这个空对象上。构造函数之所以叫“构造函数”,就是说这个函数的目的,就是操作一个空对象(即this对象),将其“构造”为需要的样子。

3.

如果构造函数内部有return语句,而且return后面跟着一个对象,new命令会返回return语句指定的对象;否则,就会不管return语句,返回this对象。

var Vehicle = function () {
this.price = 1000;
return 1000;
};

(new Vehicle()) === 1000
// false
上面代码中,构造函数Vehicle的return语句返回一个数值。这时,new命令就会忽略这个return语句,返回“构造”后的this对象。

4.如果对普通函数(内部没有this关键字的函数)使用new命令,则会返回一个空对象。
5.

函数内部可以使用new.target属性。如果当前函数是new命令调用,new.target指向当前函数,否则为undefined

function f() {

console.log(new.target === f);

}

f() // false

new f() // true

6.只有一种用法(直接在obj对象上调用foo方法),this指向obj;其他用法时,this都指向代码块当前所在对象(浏览器为window对象)。

// 情况一
(obj.foo = obj.foo)() // window

// 情况二
(false || obj.foo)() // window

// 情况三
(1, obj.foo)() // window

上面代码中,obj.foo先运算再执行,即使它的值根本没有变化,this也不再指向obj了。可以这样理解,在JavaScript引擎内部,objobj.foo储存在两个内存地址,简称为M1M2。只有obj.foo()这样调用时,是从M1调用M2,因此this指向obj。但是,上面三种情况,都是直接取出M2进行运算,然后就在全局环境执行运算结果(还是M2),因此this指向全局环境。

7.this的动态切换,固然为JavaScript创造了巨大的灵活性,但也使得编程变得困难和模糊。有时,需要把this固定下来,避免出现意想不到的情况。JavaScript提供了callapplybind这三个方法,来切换/固定this的指向。

 函数实例的call方法,可以指定函数内部this的指向(即函数执行时所在的作用域),然后在所指定的作用域中,调用该函数。

var obj = {};

var f = function () {
  return this;
};

f() === this // true
f.call(obj) === obj // true

上面代码中,在全局环境运行函数f时,this指向全局环境;call方法可以改变this的指向,指定this指向对象obj,然后在对象obj的作用域中运行函数f。如果call方法的参数是一个原始值,那么这个原始值会自动转成对应的包装对象,然后传入call方法。

8.apply方法的作用与call方法类似,也是改变this指向,然后再调用该函数。唯一的区别就是,它接收一个数组作为函数执行时的参数,使用格式如下。

func.apply(thisValue, [arg1, arg2, ...])

9.bind方法用于将函数体内的this绑定到某个对象,然后返回一个新函数。bindcall方法和apply方法更进一步的是,除了绑定this以外,还可以绑定原函数的参数。

10.原型对象的作用,就是定义所有实例对象共享的属性和方法。这也是它被称为原型对象的含义,而实例对象可以视作从原型对象衍生出来的子对象。

11.prototype对象有一个constructor属性,默认指向prototype对象所在的构造函数。

12.

由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承。constructor属性的作用,是分辨原型对象到底属于哪个构造函数。

function P() {}
var p = new P();

p.constructor
// function P() {}

p.constructor === P.prototype.constructor
// true

p.hasOwnProperty('constructor')
// false

上面代码中,p是构造函数P的实例对象,但是p自身没有contructor属性,该属性其实是读取原型链上面的P.prototype.constructor属性。

posted @ 2017-04-01 15:18  cluod  阅读(122)  评论(0)    收藏  举报