1. 原型Prototype
1.1 构造函数
所谓"构造函数",其实就是一个普通函数,但是内部使用了this变量。对构造函数使用new运算符,就能生成实例,并且this变量会绑定在实例对象上。
function Cat(name, color) { this.name = name; this.color = color; } var cat1 = new Cat("大毛", "黄色"); var cat2 = new Cat("二毛", "黑色"); alert(cat1.name); // 大毛 alert(cat1.color); // 黄色 //这时cat1和cat2会自动含有一个constructor属性,指向它们的构造函数。 cat1.constructor == Cat; //true cat2.constructor == Cat; //true function Cat(name, color) { this.name = name; this.color = color; this.type = "猫科动物"; this.eat = function () { alert("吃老鼠"); }; } cat1.type; // 猫科动物 cat1.eat(); // 吃老鼠 //每一个实例对象,每一次生成重复内容内存,但是内存地址不一样 cat1.eat == cat2.eat; //false
1.2 实例.constructor
每个构造函数生成实例的时候 会自带一个constructor属性 指向该构造函数。对于普通对象生成实例时,constructor指向其类型的构造函数。
结论1: 实例.constructor == 构造函数
function Cat(name) { this.name = name; } var cat1 = new Cat("大毛"); cat1.constructor == Cat; //true var str1 = "123"; str1.constructor == String;//true
1.3 实例.prototype
构造函数都有一个prototype
属性,指向另一个对象。这个对象的所有属性和方法,都会被构造函数的实例继承。
对该构造函数的实例,继承的prototype对象都指向同一个。
结论2: 实例1.prototype.func == 实例2.prototype.func
function Cat(name, color) { this.name = name; this.color = color; } Cat.prototype.type = "猫科动物"; Cat.prototype.eat = function () { alert("吃老鼠") }; cat1.eat == cat2.eat;//true
// hasOwnProperty判断是自己本身的属性还是继承的
cat1.hasOwnProperty("name"); //true
cat1.hasOwnProperty("type"); //false
1.4 实例.__proto__
Javascript创建对象时(普通对象和函数对象),都会内置一个__proto__属性,指向 实例的创建函数(实例.constructor).prototype
结论3: 实例.__proto__ === 构造函数.prototype
同理: 构造函数.prototype.__proto__ === Object.prototype
2. 作用域Scope
2.1 全局变量
全局声明的变量,浏览器环境实际上声明在顶层变量"window"下。
函数内部声明变量时,未使用var关键字,会声明为全局变量。
function f1() { n = 999; } f1();//调用函数时,n被注册到全局 alert(n); // 999
alert(window.n); // 999
2.2 局部变量
只能在局部使用并可见的变量,如函数内部声明的变量
function f2() { var n = 999; alert(n);//999 } alert(n);//报错
2.3 链式作用域
父对象的所有变量,对子对象都是可见的,反之则不成立
//子对象会一级一级地向上寻找所有父对象的变量 function f1() { var n = 999; function f2() { //n对f2可见 alert(n); // 999 } }
3. 闭包Closure
什么是闭包; 定义在一个函数内部的函数 (闭包就是能够读取其他函数内部变量的函数)
//下面的f2就是一个闭包 function f1() { var n = 999; function f2() { alert(n); } return f2; } var result = f1(); result(); // 999
//注意result后跟的(),这对括号才是实际调用
用途:
- 读取函数内部的变量
- 让函数内部变量的值始终保持在内存中
闭包执行时的this指针指向问题
var name = "The Window"; var object = { name: "My Object", getNameFunc: function () { return function () { return this.name; }; } }; alert(object.getNameFunc()());//The Window
//上面这句解开后等于
alert(function () { return this.name; }()); //此时this指针指向当前域下的name="The Window"
var name = "The Window"; var object = { name: "My Object", getNameFunc: function () { var that = this; return function () { return that.name; }; } }; alert(object.getNameFunc()());//My Object //分解如下 alert(function () { return that.name; }());//that是对object内部this变量的引用, object内部this指向实例本身 alert(function () { return object.name; }());//最终如此
refers:
http://www.ruanyifeng.com/blog/2010/05/object-oriented_javascript_encapsulation.html
http://www.ruanyifeng.com/blog/2009/08/learning_javascript_closures.html