- Function 类型
/*函数是对象,函数名是指针*/
function sum(num1, num2){
return num1 + num2;
}
alert(sum(10, 20)); // 20
var anotherSum = sum; // 使用不带圆括号的函数名是访问函数指针,而非调用函数
alert(anotherSum(10, 10); // 20
sum = null;
alert(anotherSum(10, 10)); // 20
// ==========
/*函数声明与函数表达式*/
// 解析器会率先读取函数声明,并使其在执行任何代码之前可用(可以访问);
// 至于函数表达式,则必须等到解析器执行到它所在的代码行,才会被真正被解释执行。
//
alert(sum(10, 10));
// 函数声明
function sum(num1, num2){
return num1 + num2;
}
// 函数表达式
sum = function(num1, num2){ // 执行会报错
return num1 + num2;
}
// ==========
/*函数名本身就是变量,函数可以作为值来使用*/
// 1.作为参数传递;2.作为函数结果返回
function callSomeFunction(someFunction, someArgument){
return someFunction(someArgument);
}
// 要访问函数的指针而不执行函数的话,必须去掉函数名后面的那对圆括号
// ==========
/*函数内部属性 arguments 和 this*/
// arguments 还有一个名叫 callee 的属性,该属性是一个指针,指向拥有这个 arguments 对象的函数
// 阶乘函数(一般用到递归算法)
function factorial(num) {
if(num <= 1){
return 1;
}else{
return num * factorial(num - 1); //问题:函数执行与函数名factorial紧紧耦合了
}
}
// 使用 callee 属性 解决 耦合
function factorial(num){
if(num <= 1){
return 1;
}else{
// 严格模式下访问 callee 会导致错误
return num * arguments.callee(num -1);// 解除了函数体内的代码与函数名的耦合状态了
}
}
//
var trueFactorial = factorial; //实际上是在另一个位置上保存了一个函数的指针。
factorial = function(){
return 0;
}
alert(trueFactorial(5)); //120
alert(factorial(5)); // 0
//=== this
// 在调用函数前,this的值并不确定,因此 this 可能会在代码执行过程中引用不同的对象。
window.color = 'red';
var o = {
color: 'blue'
}
function sayColor(){
alert(this.color);
}
// 函数的名字仅仅是一个包含指针的变量而已.
o.sayColor = sayColor;
o.sayColor();
// 即使在不同的环境中执行,全局的 sayColor() 函数与 o.sayColor() 指向的仍然是同一个函数
// 只是执行作用域不同
// ==========
/*函数属性和方法*/
// 每个函数都包含两个非继承而来的方法:apply() 和 call()
// 用途:在特定的作用域中调用函数,实际等于设置函数体内this对象的值。
// apply(运行函数的作用域, 参数数组)
// call(运行函数的作用域, 参数列表)
window.color = 'red';
var o = {
color: 'blue'
};
function sayColor(){
alert(this.color);
}
sayColor();
sayColor.call(this);
sayColor.call(window);
sayColor.call(o);
// 使用call 或 apply 来扩充作用域的最大好处,就是对象不需要与方法有任何耦合关系
// ==== bind() 创建一个函数的实例,其 this的值会被绑定到传给 bind() 函数的值
window.color = 'red';
var o = {
color: 'blue'
}
function sayColor(){
alert(this.color);
}
var objectSayColor = sayColor.bind(o);
objectSayColor(); // blue
- 面向对象
/*任何函数,只要通过 new 操作符来调用,那它就可以做为 构造函数*/
function Person(name, age, job){
this.name = name;
this.age = age;
this.job = job;
this.sayName = function(){
alert(this.name);
};
}
// 当作构造函数使用
var person = new Person('lisi', 29, 'software engineer');
person.sayName(); // lisi
// 作为普通函数调用
Person('wangwu', 22, 'doctor'); // 添加的window
sayName(); // wangwu
// 在另一个对象的作用域中调用
var o = new Object();
Person.call(o, 'zhangsan', 33, 'nurse');
o.sayName(); // zhangsan
// =============
/*
* 每个函数都有一个 prototype 属性,这个属性指向函数的原型对象。
* 默认情况下,所有原型对象都会自动获得一个 constructor 属性
*/
function Person(){
}
Person.prototype.name = 'lisi';
Person.prototype.age = 33;
Person.prototype.job = 'software engineer';
Person.prototype.sayName = function(){
console.log(this.name);
};
// 简单的原型语法
// 将 Person.prototype 设置为一个 以 对象字面量形式创建的新对象
// 结果相同,但是 constructor属性 已经不指向 Person 了
// 本质上 重写了默认的 prototype 对象,因此 constructor 属性也就变成了新对象的 constructor属性(指向 Object构造函数)
// 尽管 instanceof 操作符还能返回正确的结果,但通过constructor已经无法确定对象的类型了
Person.prototype = {
constructor: Person, // 将 constructor 设置回适当的值
name: 'lisi',
age: 33,
job: 'software engineer',
sayName: function(){
console.log(this.name);
}
}
var person1 = new Person();
var person2 = new Person();
person1.name = 'wangwu';
console.log(person1.name);
console.log(person2.name);
// hasOwnProperty() 检测一个属性是存在与 实例中,还是存在于 原型中
// true:只在给定属性中存在于对象实例中
// for in 由于 in 操作符只要通过对象能够访问到属性就返回 true
// 而 hasOwnProperty() 只在属性存在于对象实例中才 返回 true
配合(图 1-1)
2.原型的动态型
// =========
/*
* 原型的动态型
*/
function Person() {
}
var friend = new Person();
// 重写原型对象后,把原型修改为另外一个对象就等于切断了 构造函数与最初原型之间的联系。
Person.prototype = {
constructor: Person, // 将 constructor 设置回适当的值
name: 'lisi',
age: 33,
job: 'software engineer',
sayName: function(){
console.log(this.name);
}
}
friend.sayName(); // error
// 实例中的指针 仅指向原型,而不指向构造函数
//=====
/*
* 创建自定义类型 组合使用 构造函数模式 + 原型模式
*/
// 构造函数模式( 用于定义属于每个实例的属性值,同属性名但不同值)
function Person(name, age, job) {
this.name = name;
this.age = age;
this.job = job;
this.friends = ['shelby', 'court'];
}
// 原型模式(用于定义 方法和属性 的 共享!!!)
Person.prototype = {
constructor: Person, // 将 constructor 设置回适当的值
sayName: function(){
console.log(this.name);
}
};
var person1 = new Person('nicholas', 29, 'software engineer');
var person2 = new Person('greg', 22, 'doctor');
person1.friends.push('van');
console.log(person1.friends);
console.log(person2.friends);
console.log(person1.friends === person2.friends);
console.log(person1.sayName === person1.sayName);
// 每个实例属性都是在构造函数中定义的,而由所有实例共享的属性 constructor 和 方法则是在原型中定义的
配合图(1-2)
- 继承
/*
* 每个函数都有一个 prototype(原型) 属性,这个属性是一个指针,指向一个对象,
* 而这个对象的用途是包含可以由(特定类型的所有实例共享的属性和方法)
*/
/*
* 构造函数、原型、实例的关系
* 1.每个构造函数都有一个 原型对象
* 2.原型对象都包含一个指向构造函数的指针
* 3.实例都包含一个指向原型对象的内部指针
*/
function SuperType(){
this.property = true;
}
SuperType.prototype.getSuperValue = function(){
return this.property;
}
function SubType(){
this.subProperty = false;
}
// 继承了 SuperType
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function(){
return this.subProperty;
}
var instance = new SubType();
console.log(instance.getSubValue());
console.log(instance.getSuperValue());