JavaScript基础之二 (题目偏多)

数组实际上也是一个对象

继承

1. 原型链继承

        Professor.prototype = {
            name:'Mr.Zhang',
            tSkill:'JAVA'
        }
        function Professor(){}

        var professor = new Professor();

        Teacher.prototype = professor;
        function Teacher(){
            this.name = 'Mr.Wang',
            this.mSkill = 'JS/JQ'
        }

        var teacher = new Teacher();

        Student.prototype = teacher;
        function Student(){
            this.name = 'Mr.Li',
            this.pSkill = 'HTML/CSS'
        }

        var student = new Student();
        console.log(student);

思考:
学生需不需要继承老师和教授身上的所有属性?
像名字这种是没必要继承的
所以原型链这种不友好 -->尝试用call和apply来解决问题

2. call、apply

        function Teacher(name,mSkill){
            this.name = name;
            this.mSkill = mSkill;
        }

        function Student(name,mSkill,age,major){
            // 我们这里要用到teacher的属性
            Teacher.apply(this,[name,mSkill]);
            this.age = age;
            this.major = major;
        }

        var student = new Student('lili','js','13','Computor');
        console.log(student);
  1. 借用别人的属性和方法的时候,使用这种方法来做
  2. 这种方法没有办法继承Teacher的原型
  3. 这种也不算继承

3. 组合继承

存在问题:构造函数复用

    function Teacher(name,mSkill){
            this.name = name;
            this.mSkill = mSkill;
        }

    var t = new Teacher();

        Student.prototype = t;
        function Student(name,mSkill,age,major){
            // 我们这里要用到teacher的属性
            Teacher.apply(this,[name,mSkill]);
            this.age = age;
            this.major = major;
        }

        var student = new Student('lili','js','13','Computor');
        console.log(student);

4. 寄生组合继承(经典继承)

5. 仅继承原型

        function Teacher(){
            this.name = 'Mr.Li';
            this.tSkill = 'JAVA';
        }

        Teacher.prototype = {
            pSkill:'JS/JQ'
        }

        var t = new Teacher();
        console.log(t);

        function Student(){
            this.name = 'Mr.Wang';
        }

        //要注意这两句的顺序!
        //这样就继承了Teacher的原型,没继承不需要的内容
        Student.prototype = Teacher.prototype;

        // 这个时候想在学生原型上加点属性
        //但是这样,Teacher.prototype也添加上了这个属性
        //因为他们是相等的,他们指向同一个原型对象,你改我也改
        Student.prototype.age = 18;

        var s = new Student();
        console.log(s);

Student.prototype = Teacher.prototype;
因为他们是相等的,他们指向同一个原型对象,当你想在学生原型上加点属性时,你改我也改

4. 企业级继承和隔离—— 圣杯模式

借用一个中间量来中转一下,希望它是一个对象,而且拥有Teacher的原型,也就是要有一个中间的构造函数
这个构造函数实例化了以后,接收Teacher的prototype,然后再把Student.prototype等于这个中间的实例化出来的对象
这样Sdudent.prototype 与 Teacher.prototype 不是同级的

        function Teacher(){
            this.name = 'Mr.Li';
            this.tSkill = 'JAVA';
        }

        Teacher.prototype = {
            pSkill:'JS/JQ'
        }

        var t = new Teacher();
        console.log(t);

    
        function Student(){
            this.name = 'Mr.Wang';
        }


        
        function Buffer(){}
        Buffer.prototype = Teacher.prototype;
        var buffer = new Buffer();
        console.log(buffer);

        Student.prototype = buffer;
        var s = new Student();

        Student.prototype.age = 18;
        console.log(s);

封装圣杯

        function Teacher(){}
        function Student(){}
        // // function Buffer(){}

        // Buffer.prototype = Teacher.prototype;
        // var buffer = new Buffer();
        // Student.prototype = buffer;
        inherit(Student,Teacher);
        var s = new Student();
        var t = new Teacher();

        console.log(s);
        console.log(t);

        function inherit(Target,Origin){
            function Buffer(){}
            Buffer.prototype = Origin.prototype;
            Target.prototype = new Buffer();
            //被继承的一方叫做超类
            //防止构造器指向紊乱(不是系统紊乱,而是你记忆紊乱),写一下更清晰
            Target.prototype.constructor = Target;
            Target.prototype.super_class = Origin;
        }

CSS圣杯模式 双飞翼

构造函数也是一个闭包,在new的时候隐式的return了this

如果你想覆盖这个隐式返回:
你返回的是原始值,它不认 但是!你返回引用值的话就成功了

怎么样能够把圣杯模式像闭包的形式 包装一下

            var inherit = (function (){
            var Buffer = function(){};

           function inherit(Target,Origin){
                Buffer.prototype = Origin.prototype;
                Target.prototype = new Buffer();
                //被继承的一方叫做超类
                //防止构造器指向紊乱(不是系统紊乱,而是你记忆紊乱),写一下更清晰
                Target.prototype.constructor = Target;
                Target.prototype.super_class = Origin;
           }
           return inherit;
            
        })();
        
        function Teacher(){}
        function Student(){}

        inherit(Student,Teacher);
        var s = new Student();
        var t = new Teacher();

        console.log(s);
        console.log(t);

出现报错情况,把立即执行函数放在了方法调用之后,虽然是立即执行函数会立即执行,但是你执行完之后赋值给了变量,就不会继续再执行了,你调用变量的话,当然是按顺序执行,所以要写在调用之前。

ES6 extends 继承:

企业级模块化

  1. 在立即执行函数里写,相当于一个小的独立的全局
  2. 名称前加个 init前缀⑧
  3. 不同的模块 最后都放到 init()里来初始化

作业:
打印一个参数以内能被3/5/7 整除的数
打印斐波那契数列的第N位
打印从0到一个数的累加值
各自写各自的功能,然后整合在一个js里边

访问原型的两种方式:

  1. 通过构造函数.prototype
  2. 通过实例化对象.__proto __

13时

1. 链式调用

现在执行会报错,那么怎么样让它全部能够执行出来?

var sched = {
    wakeup:function(){
        console.log('running');
    },
    morning:function(){
        console.log('go shopping');
    },
    noon:function(){
        console.log('have a rest');
    },
    afternoon:function(){
        console.log('learning');
    },
    evening:function(){
        console.log('walking');
    },
    night:function(){
        console.log('sleeping');
    }
}

sched.wakeup().morning().noon().afternoon().evening().night();

每个函数里头都加 return this;
执行完一个方法的时候 返回this(就是把对象return出去) --> 就指回sched

2. this.属性名 = this[ ’ 属性名 ’ ]
3. 枚举–>遍历

在js中 有枚举就有遍历,有遍历就有枚举

4. for in

能够循环遍历对象,也能够循环遍历数组

var car = {
    brand:'Benz',
    color:'red',
    displacement:'3.0',
    lang:'5',
    width:'2.5'
}

for(var key in car){
    // console.log(car.key)  会报错
    //因为,  car.key ->car['key'] -> undefined
    //意思是它不管你是不是变量,
    //你点了之后就当成属性转换成car['key'],但是因为你对象里头没有key属性,所以报错
    console.log(key + ':' + car[key]);
}
var car  = {
    brand:'Mazda',
    color:'red'
}
console.log('displacement' in car); //false

要通过 in查找car里头有没有displacement属性,记得要加引号
它是判断属性存不存在这个对象上!所以返回的是true / false

5. obj.hasOwnProperty方法

作用:仅找对象自身的属性

它是排除原型的,但是 in 不排除

hasOwnProperty用的比较多,in不怎么用知道就行

3. instanceof (肯定会考的)

作用:判断这个对象是不是该构造函数实例化出来的

▲笔试的时候要答得出:

function Car(){
}

var  car = new Car();

console.log(car instanceof Car);

function Person(){}

var p = new Person();

console.log(p instanceof Car);  //false
console.log(car instanceof Object); //true
console.log([] instanceof Array);  //true
console.log([] instanceof Object);  //true
console.log({} instanceof Object);  //true

// A对象的原型里到底有没有B的原型? 有

三种判断数组的方法

var a = [1,23] || {}

console.log(a.constructor); //第一种

console.log(a instanceof Array); //第二种

var str = Object.prototype.toString.call(a) // 第三种,这个会经常用到的

if(str === '[object Array]'){
    console.log('是数组');
}else{
    console.log('不是数组');
}
console.log(str);

console.log(a.toString());
  • 第三种方法会经常用到
  • 要区分一下 自己.prototype.toString() 和 Object.prototype.toString()
4. callee、caller

(没啥用,在严格模式下还会报错。但是笔试喜欢考这个)

1. 获取形参个数的两种方法:

    function test(a,b,c){
        console.log(arguments.callee.length); // 3
        console.log(test.length); // 3
        console.log(arguments.length); // 4
    }
    test(1,2,4,5);

arguments.callee表示:实参列表所对应的函数是谁,它就返回哪个函数

arguments.callee 你在哪个函数里边就执行哪个函数

function sum(n){
    if(n <= 1){
        return 1;
    }
    return n + sum(n - 1);
}

改成立即执行函数的写法

2.caller

它可以打印出 谁调用它(前提是它被调用了)
返回当前被调用函数的函数引用

NaN不等于任何值 就也不等于自己啊!!!

5. this指向、构造函数的函数上下文

题1:

       function foo(){
            bar.apply(null,arguments);
            //没有指向的话,就正常执行。
            //相当于 bar(arguments)
        }

        function bar(){
            console.log(arguments);
        }

        foo(1,2,3,4,5);  //打印arguments

题2:

JS的typeof能够返回哪些值?

number、string、boolean、undefined、function、object(null)

它并不打印null!null的时候打印object

题3:

function b(x,y,z){
    arguments[2] = 10;
    alert(z);
    
    //-----------------
    z = 6;
    alert(arguments[2]);
}

b(1,2,3); //10

形参和实参是一一对应的映射关系,你改我也改

题4:

var f = (
    function f(){
        return '1';
    },
    function g(){
        return 2;
    }
)

//请问 typeof(f) 打印出来是什么?
// function
//因为 (f(),g()) 逗号返回的是最后一个
  1. 逗号运算符,
  2. 要看清后头有没有立即执行 不要因为刷题刷多了惯性思维反应为return的值了!

题5:

console.log(undefined == null); //true
console.log(undefined === null); //false
console.log(isNaN('100')); //false
console.log(parseInt('1a') == 1); //true

题:

空对象等不等于空对象?为什么不等于?怎样才能让他们相等?

答:

  1. 因为引用值对比的是地址值!两个空对象存储在不同的空间里
  2. 赋值的方法
    var obj = { };
    obj1 = obj;

题:

var a = '1';
function test(){
    var a = '2';
    this.a = '3';
    console.log(a); // '2'
}
test(); //2
new test(); // 不打印
console.log(a); // '3'

分析:
    var a = '1';
	function test(){
	    var a = '2';
	    this.a = '3';
	    console.log(a); // '2'
	    console.log(this.a);
}
test(); //2
console.log('---------------------');
new test(); // 
console.log('---------------------');
console.log(a); // '3'


// GO = {
//      a:undefined --> '1',
//      test:function test(){},
// }

// AO = {
//    this:window
//    a:undefined --> 2 
// }


// AO = {
//    this:{
//      a:3
// }
//    a:undefined --> 2 
// }

错,以为它没被调用所以不打印

它 new的时候实际上就执行了(调用了)

题:

var a = 5;
function test(){
    a = 0;
    console.log(a);
    console.log(this.a);
    var a;
    console.log(a);
}
test(); // 0,5,0
console.log('---------------------');
new test();  // 0 undefined  0

分析:
// GO = {
//     a:undefined
//        5,
//     test:function test(){}
// }

// AO = {
//    a:undefined --> 0 
// }

    // function test(){
	//    var this = {
	//                  
	//     }
    // a = 0;
    // console.log(a);
    // console.log(this.a);
    // var a;
    // console.log(a);
    // }

// AO = {
//     a:undefined --> 0
//	   this:{ }
// }

14时

1. 三元运算

条件表达式 ?是 :否

是 否里头的内容

  1. 可以直接是执行语句 且还能继续嵌套判断
  2. 它自己可以把结果返回出来(所以通常都会声明一个变量去接)

题:

var str = 89 > 9 ? (
                     '89' > '9' ? '通过了'
                                :'内层未通过'
                    )
                  : '外层未通过';
console.log(str);

字符串与字符串比较!是从第一位开始比较对应的ASCII码 (笔试的时候千万不能失分啊!)

2. 克隆/复制/拷贝
  • 赋值
var person1 = {
    name: 'zhangsan',
    age: 19,
    sex: 'male',
    height: 174,
    weight: 150
}

var person2 = person1
  • clone,声明个空对象,for循环,往里填东西 (这样对象的地址不一样了)
    var person2 = {};

    for(var key in person1){
        person2[key] = person1[key];
    }
}
  • 引用值的克隆
1.浅拷贝

只处理了第一层的属性,没有处理下面的引用值
对于引用值属性,还是拿了别人的引用空间

在这里插入图片描述

注意!
Object.protorype自定义的属性,在for循环时也被放到 person2里了。要剔除出去,只拷贝person1的属性

  • 怎么样把原型给剔除出去 - hasOwnProperty
    在这里插入图片描述
    单独的一段for循环代码不好看,将它封装一下,同时剔除原型上的属性

浅拷贝函数:

function clone(origin,target){
    //如果用户没有填target参数
    var target = target || {};
    for(var key in origin){
        if(origin.hasOwnProperty(key)){
            target[key] = origin[key];
        }
        
    }
    return target;
}
2. 深拷贝

最后要达到的目的:不管对象里边是引用值还是原始值,我改变了我自己的内容,怎么操作都和你没有关系
有没有传值
首先判断 这个属性是不是我自己的还是原型上的
然后判断这个属性是原始值还是引用值。 是不是 对象类型的 (因为历史遗留问题,所以还要判断下这个属性 !==null
再然后,判断是数组还是对象

// 有引用值的时候要做一系列相关的遍历,
// 判断里头每一项键值对是不是引用值
// 是引用值的话,则判断它是数组还是对象。
//进去后再判断里头每一项键值对是不是引用值,如果是再继续

var person1 = {
    name: 'zhangsan',
    age: 19,
    sex: 'male',
    height: 174,
    weight: 150,
    children: {
        first: {
            name: 'zhangyi',
            age: 13
        },
        second: {
            name: 'zhangsaner',
            age: 10
        },
        third: {
            name: 'zhangsanan',
            age: 9
        }
    },
    car: ['Benz','Mazda']

}

var person2 = deepClone(person1);
person2.children.forth = {
    name:'zhangsajkh',
    age: 3
};
person2.car.push('volvo');
console.log(person1,person2);

function deepClone(origin,target){
    // 防止用户不传值
    var target = target || {},
        toStr = Object.prototype.toString,
        arrType = '[object Array]';

    for(var key in origin){
        // 先判断这个属性是不是origin的
        if(origin.hasOwnProperty(key)){
            // 再判断它是不是引用值     注意! typeof(null)打印出来的也是object 
            if(typeof(origin[key]) === 'object' && origin[key] !== null){
                // 再判断这个引用值是数组还是对象,是数组则创建空数组,对象创建空对象
                if(toStr.call(origin[key]) === arrType){
                    target[key] = [];
                }else{
                    target[key] = {};
                }

                // 再递归,拷贝引用值
                deepClone(origin[key],target[key])
            }else{
                target[key] = origin[key];
            }
        }
    }

    return target;

}

笔试题:

function test(){
    console.log(foo);                                  //undefined                       
    var foo = 2;
    console.log(foo);                				//2
    console.log(a);							//undefined
}
test();

错!!! console.log(a);会报错
打印出:a is not defined
都没有声明啊!!(这个笔试千万不能错 哭)


function a(){
    var test;
    test();
    function test(){
        console.log(1);
    }
}
a();  // 1

// a执行的时候 test会被执行
  1. 这题是关于this指向很难的题哦!
var name = '222';
var a = {
    name:'111',
    say:function(){
        console.log(this.name)
    }
}
var fun = a.say;
fun(); // '222'
a.say(); // '111'
var b = {
    name:'333',
    say:function(fun){
        fun();
    }
}
b.say(a.say); // '222'
b.say = a.say;
b.say(); // '333'

4.关于this指向

function test(){
    var marty = {
        name:'marty',
        printName:function(){
            console.log(this.name);
        }
    }
    var test1 = {
        name:'test1'
    }

    var test2 = {
        name:'test2'
    }
    var test3 = {
        name:'test3'
    }

    test3.printName = marty.printName;
    marty.printName.call(test1);                    //test1
    marty.printName.apply(test2);                   //test2
    marty.printName();                              //marty
    test3.printName();                              //test3

}

test();
var bar = {
    a:'1'
};

function test(){
    bar.a = 'a';
    Object.prototype.b = 'b';
    return function inner(){
        console.log(bar.a);
        console.log(bar.b);
    }
}
test()();                       	// a b

作业:

1.

function Foo(){
    getName = function(){
        console.log(1);
    }
    return this;
}
Foo.getName = function(){
    console.log(2);
}
Foo.prototype.getName = function(){
    console.log(3);
}
var getName = function(){
    console.log(4);
}
function getName(){
    console.log(5);
}

//这些打印出什么?
Foo.getName();
getName();
Foo().getName();
getName();
new Foo.getName();
new Foo().getName();
new new Foo().getName();

分析:
Foo.getName();
getName();
Foo().getName();  				//1
getName();
new Foo.getName();				// new 2 -->2
new Foo().getName();			// (new Foo()).getName()  --> 到this里头没有,到原型里头去找,有找到 3
new new Foo().getName();		// new 3  -->3
  1. 点运算 比 new 的优先级高
  2. 括号的优先级大于点
  3. new Foo( ) 有括号有new的时候,他们是一体的
    实例化过后再调用方法
    怎么样才能访问到原型上面
    构造函数实例化了以后才有可能访问到原型上面
    只要后边的有结果的前面怎么new 都没有用

运算符优先级表格
在这里插入图片描述

2. 请用 window.prompt接收用户输入的年份,判断是否是闰年?(用三元运算来做)

判断闰年的条件:
① 闰年能被4整除,但是不能被100整除
② 能被400整除

两个条件二选一就可以实现判断,当然也可以将两个条件都写进去

var year = parseInt(window.prompt('请输入年份:'));
function isLeapYear(year){
    var runYear = (year % 4 === 0 && year %100 !==0) || (year % 400 === 0) ? '是闰年' : '不是闰年';
    console.log(runYear);
}

isLeapYear(year);
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值