这里首先说明下js中new关键字的作用
1.创建一个新的空对象。
2.将该对象的 __proto__ 指向构造函数的prototype(原型对象)。
3.将构造函数内的 this 指向新创建的对象。
4.执行构造函数内的代码,为对象添加属性和方法。
5.返回新创建的对象。
1.同一个构造函数的多个实例之间 无法共享属性(创建多个实例的时候会造成资源浪费)
function Cat(name, color) {
this.name = name;
this.color = color;
this.meow = function () {
console.log('miao');
};
}
var cat1 = new Cat('LH', 'White');
var cat2 = new Cat('EH', 'Black');
cat1.meow === cat2.meow
// false
上面代码中,cat1和cat2是同一个构造函数的两个实例都具有meow方法
由于meow方法是生成在每个实例对象上面,所以两个实例就生成了两次
也即每新建一个实例就会新建一个meow方法
这既没有必要,又浪费系统资源,因为所有meow方法都是同样的行为,完全应该共享
这种缺点的解决方法即是JS的原型对象(prototype)
2.prototype
JS继承机制的设计思想是原型对象的所有属性和方法,都能被实例对象共享
上述缺点的解决方法理由: 也即若属性和方法定义在原型上则所有的实例对象都可以共享,从而节省内存并且体现出实例对象之间的联系
下面是为对象指定原型
JS规定每个函数都有一个prototype属性用于指向一个对象
function f() {}
typeof f.prototype // "object"
上面代码中,函数f默认具有prototype属性,指向一个对象
对于普通函数来说,该属性基本无用
但是对于构造函数来说,生成实例的时候,该属性会自动成为实例对象的原型
function Animal(name) {
this.name = name;
}
Animal.prototype.color = 'white';
var cat1 = new Animal('LH');
var cat2 = new Animal('EH');
cat1.color // 'white'
cat2.color // 'white'
上面代码中构造函数Animal的prototype属性,就是实例对象cat1和cat2的原型对象
原型对象上添加一个color属性则实例对象都共享该属性
原型对象的属性不是实例对象自身的属性
只要修改原型对象,变动就立刻会体现在所有实例对象上,当实例对象本身没有某个属性或方法的时候,它会到原型对象去寻找该属性或方法(否则直接使用本身的属性和方法)
如:
cat1.color = 'black';
Animal.prototype.color = 'yellow';
cat1.color // "black"
cat2.color // "yellow"
总结一下原型对象的作用,定义所有实例对象共享的属性和方法
3.prototype的constructor属性
prototype对象有constructor属性默认指向prototype对象所在的构造函数,由于constructor属性定义在prototype对象上面,意味着可以被所有实例对象继承
function P() {}
var p1 = new P();
p1.constructor === P // true constructor属性的作用:可以得知某个实例对象,到底是哪一个构造函数产生的
p1.constructor === P.prototype.constructor // true
p1.hasOwnProperty('constructor') // false 继承的所以是false,本身没有这个属性
由于constructor属性我们可以从一个实例对象新建另一个实例
function Constr() {}
var x = new Constr();
var y = new x.constructor();
y instanceof Constr // true
constructor属性表示原型对象与构造函数之间的关联关系
如果修改了原型对象,一般会同时修改constructor属性,防止引用的时候出错
function Person(name) {
this.name = name;
}
Person.prototype.constructor === Person // true
Person.prototype = {
method: function () {}
};
Person.prototype.constructor === Person // false
Person.prototype.constructor === Object // true
如果不能确定constructor属性是什么函数,还有一个办法:通过name属性,从实例得到构造函数的名称
funciton Foo() {};
var f = new Foo();
f.constructor.name // "Foo"
4.__proto__属性
简单记就是:构造函数的原型对象prototype会等于实例对象的__proto__属性
var A = function (){}
var a = new A()
console.log(a.__proto__ === A.prototype) // true
5.模块化思想-封装私有变量(不暴露私有变量)
使用IIFE(Immediately-Invoked Function Expression)
将相关属性和方法封装在一个函数作用域中从而不暴露私有成员
var module1 = (function ($) {
var _count = 0;
var m1 = function () {
// some code
};
var m2 = function () {
// some code
};
return {
m1: m1,
m2: m2
};
})(jQuery);
使用上面的方法外部代码无法读取内部的_count变量,上面的module1就是 JavaScript 模块化的基本写法