手记

javascript高级程序设计(第3版)之 学习笔记

  1. 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
  1. 面向对象
/*任何函数,只要通过 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)

  1. 继承
/*
        *   每个函数都有一个 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());
1人推荐
随时随地看视频
慕课网APP