1. 原始类型和对象类型
var n = 10;
var m = n; // 传值赋值,m的值等于n
m = 13;
console.log('n = %d, m = %d.', n, m); // n = 10, m = 13.
var onePerson = {}; // 新建一个空对象
onePerson.fullname = 'HarryPotter'; // 为对象新建属性fullname
onePerson.age = 21; // 为对象新建属性age
onePerson.talk = function () {
console.log('Hi, my name is %s. My age is %d.', this.fullname, this.age);
} // 为对象新建方法talk,在对象的方法中,this指向该对象
var otherPerson = onePerson; // 对象赋值是引用赋值,otherPerson就是onePerson,二者共同指向一块内存地址。
otherPerson.fullname = 'Kate'; // 等同于修改了onePerson.fullname
onePerson.talk(); // Hi, my name is Kate. My age is 21.
2. 将函数作为构造函数
javascript的函数主要有三种调用方式。作为函数直接调用,作为对象的方法调用,作为对象的构造函数调用。
function Person() {
global_firstname = 'funway'; // 定义一个全局变量,无法被对象继承
var local_lastname = 'wang'; // 定义一个局部变量,无法被对象继承
this.fullname = 'funway.wang'; // 定义一个继承属性,可以被对象继承
console.log('In Person function as a constructor.');
}
Person(); // 直接作为函数调用,打印 "In Person function as a constructor."
AA = new Person(); // 作为构造函数调用, 同样会打印 "In Person function as a constructor."
console.log(global_firstname); // "funway"
console.log(AA.global_firstname); // undefined
console.log(AA.local_lastname); // undefined
console.log(AA.fullname); // "funway.wang"
上面的代码中,我们通过将Person函数作为构造函数创建了一个新的对象AA,用C++的面向对象来看,函数名Person就相当于一个类名。
实际上,Person作为一个javascript函数,默认有一个prototype属性。prototype属性值是一个对象,我们叫做原型对象。当函数作为构造函数被调用时候,该prototype原型对象就会被当作新对象的原型,所有新创建的对象均有一个__proto__对象,指向该原型对象。另外,prototype原型对象内部有一个constructor属性,指向构造函数Person,这个constructor负责调用构造函数对新对象进行初始化。可以这么说,AA = new Person() 相当于执行了以下三步:
AA = {}; // 创建空对象
AA.__ptoto__ = Person.prototype;
执行AA.__proto__.constructor指向的函数对AA进行初始化,创建AA对象的属性
上图中的Object与Function这俩个底层的概念这里就不多解释了,javascript的Object与Function的关系看到哭。。。=。=#
3. prototype原型,原型链与动态继承
从上面可以看出,由Person构造函数构造的对象,都有一个默认的__proto__属性指向Person.prototype,那么我对Person.prototype的修改都会实时的传递到所有Person对象上。另外,对象可以直接通过.属性名/.方法名访问到其原型对象的属性或者方法,前提是该对象本地没有重名的属性/方法。这就是javascript动态继承的基础。而原型链的意义就是,要访问一个对象x的属性/方法的时候,会先查找对象本地空间,没有,则查找x.__proto__空间,然后再x.__proto__.__proto__。这样递归直到找到所要的属性/方法或到达底层的Object基本对象。
function Person(name) {
this.name = name? name : 'noname';
}
bill = new Person('bill'); // 创建新对象
kate = new Person('kate'); // 创建新对象
console.log(bill.name); // "bill"
console.log(bill.age); // undefined,bill对象没有该属性
Person.prototype.age = 18; // 增加age属性,所有的Person对象都自动拥有该属性。
Person.prototype.sayHi = function() {
console.log('hi, my name is %s, i am %d yeas old.', this.name, this.age);
} // 增加sayHi方法,所有的Person对象都自动拥有该方法
bill.sayHi(); // "hi, my name is bill, i am 18 yeas old."
kate.sayHi(); // "hi, my name is kate, i am 18 yeas old."
bill.age = 25; // 给bill对象添加了一个本地属性age,之后bill.age将不再访问bill.__proto__.age
console.log(bill.age); // 25,访问的是bill.age(不会再跳进去访问bill.__proto__.age了)
console.log(kate.age); // 18,访问的是kate.__proto__.age(因为kate.age不存在)
var Programer = function(name) {
this.name = name? name : 'noname';
}
Programer.prototype.__proto__ = Person.prototype;
Programer.prototype.skill = function() {
console.log('coding');
}
var jim = new Programer('jim');
jim.sayHi(); // 调用的是jim.__proto__.__proto__.sayHi()
jim.skill(); // 调用的是jim.__proto__.skill

