1. 关于链式调用
var sched = {wakeup: function () {console.log('Running');return this;},morning: function () {console.log('Going shopping');return this;},noon: function () {console.log('Having a rest');return this;},afternoon: function () {console.log('Studying');return this;},evening: function () {console.log('Walking');return this;},night: function () {console.log('Sleeping');return this;}}// 实现链式调用的关键是每次函数调用后返回this,jquery里面的链式调用原理也是如此sched.wakeup().morning().noon().afternoon().evening().night();
2. 如何访问对象的属性
var myLang = {No1: 'HTML',No2: 'CSS',No3: 'JavaScript',myStudyingLang: function (num) {console.log(this['No' + num]);//直接拼接 this.No + num 会报错}}myLang.myStudyingLang(1); // 返回'HTML'//例如obj = {name: '潘小姐'}console.log(obj['name'])//访问obj.name的时候,js引擎在内部做了隐式转换 obj['name']
3. 对象枚举,一组有共同特性的数据集合叫枚举。
遍历,一组信息内,按顺序的一个一个获取其信息的过程叫做遍历的过程,有枚举就一定有遍历。
var car = {brand: 'banz',color: 'red',displacement: '3.0'}for(var key in car){console.log(car.key);//返回三个undefined,原因是因为系统内置隐式转换成了car['key'],但是系统 找不到这个值,所以返回undefinedconsole.log(car[key]);//可以打印}
for in 既可以遍历对象,也可以遍历数组,区别也不大。
用for in遍历实例化出来的对象,可以打印出自定义的包括原型链上的值和属性。
function Car() {this.brand = 'Benz';this.color = 'red';this.displacement = '3.0';}Car.prototype = {lang: 5,width: 2.5}Object.prototype.name = 'Object';var car = new Car();for (var key in car) {if(car.hasOwnProperty(key)) {console.log('自身属性' + key + ':' + car[key]);//brand, color, displacement} else {console.log('原型链上的属性' + key + ':' + car[key]);//lang, width, name}}//hasOwnProperty,返回布尔值,只找对象自身的属性,排除掉包括原型上的不是自己的属性。var newCar = {color: 'red',brand: 'banz'}console.log('displacement' in newCar); 返回false 系统内置隐式的做了转换 newCar['displacement'] ,不打双引号会报错function Car2(){this.color = 'red';this.brand = 'banz';}Car2.prototype.displacement = '3.0';var car2 = new Car2();console.log('displacement' in car2);//true, 判断这个属性在不在 后面的值上,不排除原型
4. instanceof 判断这个对象是不是该构造函数实例化出来的(A对象的原型里到底有没有B构造函数的原型)
function Tree(){}var tree = new Tree();console.log(tree instanceof Tree);//trueconsole.log(tree instanceof Object);//trueconsole.log([] instanceof Object);//trueconsole.log([] instanceof Array);//trueconsole.log({} instanceof Object);//truevar a = [];console.log(a.constructor); //Arrayconsole.log(a instanceof Array);//true
5. 经验
var str = Object.prototype.toString.call(a);console.log([1, 2, 3].toString());//1,2,3console.log(str);//[object Array]// Object.prototype = {// toString:function(){// this.toString();// }// }//实际上就是函数里面的this替换成了a
判断是不是数组,常用的方法 ⬇
var str1 = Object.prototype.toString.call(a);if(str1 === '[object Array]'){console.log('是数组');}else{console.log('不是数组');}
6. 关于this
function test(b){this.d = 4;var a = 1;function c(){}}test(123);console.log(this.d);//4console.log(window.d);//4console.log(d);//4// AO = {// arguments: [1, 2, 3],// this: window,// b: 123,// a: undefined -> 1,// c: function(){}// }//在普通函数内部,只要没有实例化这个函数,这个函数的this是默认指向的window.
构造函数的this指向
function Test(){//var this = {// __proto__: Test.prototype//}this.name = '123';}var test = new Test();
//预编译的时候,AO指向window,当new Test()的时候就执行了,GO里面产生了Test和test,且当new的时候Test内部var 了this,AO内部的this就被覆盖了,形成了原型链,this就指向了实例化的对象,test在全局
// AO = {// this: window --> this:{name: 123, __proto__: Test.prototype}// }// Go = {// Test: function(){},// test: {// name: 123,// __proto__: Test.prototype// }// }
7. call/apply
function Person(){this.name = '张三';this.age = 18}function Programmer(){Person.apply(this);this.work = 'teacher';}var p = new Programmer();console.log(p);//Programmer {name: '张三', age: 18, work: 'teacher'}//apply把实例化出来的对象里的this将Person里面的this替换了
1.全局的this指向window
2.预编译阶段函数的this也指向window
3.call/apply改变this指向
4.构造函数的this指向实例化的对象
8.callee
function test02(a, b, c){console.log(arguments.callee);//arguments.callee返回的是正在被执行的函数对象,当执行到这一 句的时候,arguments所指向的函数是谁,就返回谁console.log(test02.length);//打印该函数形参的长度console.log(arguments.length);//打印实参的长度}test02();function test_01(){console.log(arguments.callee);function test_02(){console.log(arguments.callee);}test_02();}test_01();//打印的都是两个函数的引用
9. 用递归的方式做第n位的累加
function addSum(n){if(n <= 1){return 1;}return n + addSum(n - 1);}console.log(addSum(10));
//当上面的函数写成了立即执行函数,无法直接写函数名,就可以用上arguments.callee找到这个函数
var res = (function(n){if(n <= 1){return 1;}return n + arguments.callee(n - 1);})(10);console.log(res);//55
10. caller 打印调用当前函数的函数引用,谁当前调用了这个函数,就返回哪个函数(严格模式下会报错),在被调用的函数打印这个函数的caller,就可以打印出谁调用了它
test_03();function test_03(){test_04();}function test_04(){console.log(test_04.caller);//打印出来是test_03()整个函数}
笔试/面试题 部分
1. 壹
function foo(){bar.apply(null, arguments)}function bar(){console.log(arguments);}foo(1, 2, 3, 4, 5)
//结果打印1, 2, 3, 4, 5.事实上,每个函数的执行都相当于 函数名.call(),现在是bar.apply(),apply的第一个值又是null,this指向并没有更改,arguments传的值是数组,而 bar的参数又是空的,也就是相当于给bar传值并且执行,所以是1, 2, 3, 4, 5
2. JS的typeof能返回的值有哪些, string,number,boolean,undefined,object,function
3. 叁
function b(x, y, a){arguments[2] = 10;console.log(a);//10}b(1, 2, 3);//实参与形参是相互映射的关系,你改我也改,我改你也改
4. 肆
var f = (function f(){return '1';},function g(){return 2;})console.log(typeof f);//function,逗号运算符,所以肯定返回最后面的函数 ,函数typeof出来返回 functionvar f = (function f(){return '1';},function g(){return 2;})();console.log(typeof f);//number,逗号运算符,所以肯定返回最后面的函数,又有括号,成为了表达式相当于f() ,typeof(2)出来返回number
5. 伍
console.log(undefined == null);//trueconsole.log(undefined === null);//falesconsole.log(isNaN(100));//falesconsole.log(parseInt('1a') == 1);//true,parseInt从头开始找,直到出现非数为止,再隐式类型转换成number,最后再parseIntfunction isNaN1(num){var res = Number(num) + '';if(res == 'NaN'){return true;}else{return false;}}console.log(isNaN1('123'));//false NaN不等于任何数,包括自己
6. { } == { } 等不等于?为什么不等于?怎样让它等于?
因为引用值对比的是地址
var obj = { };
obj1 = obj;
这个时候就相等
7. 柒
var a = '1';function test_05(){var a = '2';this.a = '3';console.log(a);}test_05();//打印的var a = '2';new test_05();//打印的是a,不是this.a,所以还是2console.log(a);//打印this.a = '3';
8. 捌
var n = 5;function test_06(){n = 0;console.log(n);console.log(this.n);var n;console.log(n);}test_06();//第一个console.log是0,第二个this.n是找外面的n所以是5,第三个还是0new test_06();//第一个console.log找自己,有肯定打印自己所以是0,实例化确实存在this,但是没有this.n这个属性,所以undefined,第三个还是0//结果返回0, 5, 0, 0, undefined, 0
作业部分
1. 写一辆车的构造函数,再写一个人的构造函数,用apply借用车的属性
function Car(brand, color, displacement){this.brand = brand;this.color = color;this.displacement = displacement; //排量this.info = function(){return '排量为' + this.displacement.toFixed(1) + '的' + this.color + this.brand;}}function Person(opt){Car.apply(this, [opt.brand, opt.color, opt.displacement]);this.name = opt.name;this.age = opt.age;this.say = function(){console.log('年龄为'+ this.age + '的' + this.name + '买了一辆' + this.info());}}var p = new Person({color: '红色',displacement: 3.0,brand: 'banz',name: '潘小姐',age: 18})p.say();
