一、构造函数中的this指向
- 构造函数在没有实例化之前,this是指向window的
构造函数在实例化之后,this是指向当前这个实例化对象本身
// 构造函数实例化的原理// 构造函数在没有实例化之前,this是指向window的// 构造函数在实例化之后,this是指向当前这个实例化对象本身function Car(opt){this.color = opt.color;this.brand = opt.brand;}// 在此时构造函数本没有实例化,函数也没有执行,那么里面的this是没有意义的// 把构造函数当做普通函数执行,此时构造函数并没有实例化;那么此时的this是指向window的// Car();// 构造函数实例化后,this就指向当前实例化的对象本身了var car1 = new Car({color: 'red',brand: '比亚迪'});var car2 = new Car({color: 'black',brand: '大众'});console.log(car1.color);console.log(car2.color);
二、构造函数实例化原理
构造函数执行时,形成自己的AO;形成自己的执行期上下文时,首先会创建一个this空对象
- 构造函数执行过程中,new的作用其实就是为了改变this指向
- 当JS引擎看到new执行的时候,首先会在AO里面保存一个this空对象
- 在构造函数执行过程中,this.xxx;都是在给这个this空对象设置私有属性和方法
最后JS引擎会在构造函数末尾隐式加上 return this;
- 如果我们自己写了return,且return后面跟的是一个原始值,那么还是默认隐式返回 return this
如果我们自己写了return,且后面跟的是引用类型的值,那么就返回我们自己写的引用值
// 构造函数实例化原理// 1. 构造函数在执行时,形成AO后,首先保存this对象// 2. 构造函数执行过程中,new的作用其实就是为了改变this指向// 3. 当JS引擎看到new执行的时候,首先会在AO里面保存一个this空对象// 4. 在构造函数执行过程中,this.xxx;都是在给这个this空对象设置私有属性和方法// 5. 最后JS引擎会在构造函数末尾隐式加上 return this;// + 如果我们自己写了return,且return后面跟的是一个原始值,那么还是默认返回 return this// + 如果我们自己写了return,且后面跟的是引用类型的值,那么就返回我们自己写的引用值// GO = {// Car: function(color, brand){....},// car1:{// color: color,// brand: brand// },// car2:{// color: color,// brand: brand// }// }// AO = {// this: {// color: color,// brand: brand// }// }function Car(color, brand){// 构造函数执行时,形成AO,首先会创建一个this空对象// this.xxx; 都是给这个空对象添加属性或者是方式// this = {// color: color,// brand: brand// }this.color = color;this.brand = brand;// 不写return,或者return的是一个原始值,那么都是隐式返回return this这个对象// return this;}var car1 = new Car('red', 'Benz');var car2 = new Car('black', 'BMW');console.log(car1.brand);console.log(car2.brand);
自己模拟构造函数的实例化原理
// 自己模拟构造函数实例化的过程function Car(color, brand){var obj = {};obj.color = color;obj.brand = brand;return obj;// obj = {// color: color,// brand: brand// }}var car1 = new Car('red', 'Benz');var car2 = new Car('black', 'BMW');console.log(car1.brand);console.log(car2.brand);
三、构造函数中的return问题
3.1、构造函数中的this问题
构造函数如果不实例化且不执行,那么里面的this的没有意义的
- 构造函数如果不加new关键字执行,仅仅是当做普通函数执行,那么里面的this指向的是window
构造函数加new关键词执行,里面的this指向的是当前这个实例化对象本身
3.2、构造函数中的return问题
在构造函数中,如果我们不写return,系统会自动给我们隐式加上return this;
- 在构造函数中,如果我们写了return,但是return后面跟的是原始值类型,那么这个构造函数仍旧返回的是return this
在构造函数中,如果我们写了return且后面跟的是引用数据类型,那么就会返回的写的这个引用类型值
// 构造函数中的this问题// 构造函数如果不实例化且不执行,那么里面的this的没有意义的// 构造函数如果不加new关键字执行,仅仅是当做普通函数执行,那么里面的this指向的是window// 构造函数加new关键词执行,里面的this指向的是当前这个实例化对象本身// 构造函数中的return问题// 在构造函数中,如果我们不写return,系统会自动给我们隐式加上return this;// 在构造函数中,如果我们写了return,但是return后面跟的是原始值类型,那么这个构造函数仍旧返回的是return this// 在构造函数中,如果我们写了return且后面跟的是引用数据类型,那么就会返回的写的这个引用类型值function Car(color, brand){this.color = color;this.brand = brand;// return this; //系统默认返回// return 10; // 返回原始值,无效// return 'kola'; // 返回原始值无效// return []; // 返回引用值return {};}var car = new Car('red', 'Benz');console.log(car);
四、包装类
只有Number、String、Boolean才会有包装类
4.1、原始值是没有自己的方法和属性的
// 原始值是没有自己的属性和方法的var a = 1;a.len = 3;console.log(a.len);
4.2、当一个数字被new以后,它就成了一个实例化的对象;既然是对象,那么此时便可以设置属性和方法了
// 当一个数字被new后,那么这个数字就变成了实例化对象了;既然是对象那么此时便可以设置属性和方法了var a = 1;var b = new Number(a);b.len = 3;b.say = function(){return '我是一个包装类'};console.log(b.len);console.log(b.say());
4.3、原始值经过new包装后,如果再次参与运算,那么它最后将又返回原始值
// 原始值经过new包装后,如果再次参与运算,那么它最后将又返回原始值var a = 1;var c = 3;console.log(a + c);var b = new Number(a);b.len = 2;b.add = function(){return '我要做加法了哦';};console.log(b); // Number {1, len: 2, add: ƒ}var d = b + 1;console.log(d); // 2
4.4、系统内置的包装类
- new Number
- new String
new Boolean
// 包装类var test1 = new Number(undefined);var test2 = new Number(null);var test3 = new String('undefined');var test4 = new String('null');// Number {NaN}; Number {0}; String {'undefined'}; String {'null'}console.log(test1, test2, test3, test4);
4.5、undefined和null是无法设置属性和方法的
// undefined和null是无法设置属性和方法的console.log(undefined.len);console.log(null.len);
五、JS包装类的过程
5.1、系统包装类的问题
如果不声明变量去保存这个包装类的话,那么系统会将其删除掉
// JS包装类的过程var a = 123; // 原始值a.len = 3; // new Number(a).len = 3; JS包装类完成后,没有变量保存;所以系统会将其删除掉 deleteconsole.log(a.len);var obj = 3; // 原始值new Number(obj).name = '123'; // 包装类完成后,没有变量保存,所以系统会将其delete掉console.log(obj.name);
解决包装类无法保存的问题:声明一个变量去保存这个包装类即可
// 解决包装类无法保存的问题var a = 3;// a.len = 3; // new Number(a).len; 虽然经过了包装类,但是没有变量去保存它,解决的办法就是声明一个变量去保存它即可var b = new Number(a);b.len = 3;console.log(b.len)
5.2、字符串并没有包装类
字符串并没有包装类,之所以有str.length 是因为系统进行了包装类
// 字符串并没有包装类,之所以有str.length是因为系统内部进行了包装类var str = 'kola';// 系统内部进行了包装类console.log(str.length); //console.log(new String(str).length);
5.3、数组中的length属性和数组截断
注意:字符串的length属性是系统包装类的结果,所以字符串的length属性是无法做字符串截断的
// 数组中的length属性,可以用来做数组截断var arr = [1, 2, 3, 4, 5];arr.length = 2;console.log(arr); // [1, 2]// 字符串中的length属性是系统包装类的结果,所以无法做字符串截断var str = 'liangyu';str.length = 2;console.log(str); // liangyu
六、练习题
// 练习题var name = 'liangyu';name += 10;var type = typeof(name);if(type.length === 9){type.text = 'string'; // new String(type).text = 'string'; 没有变量保存,系统会将其删除掉}console.log(type.text); // undefined
function Test(a, b, c){var d = 1;this.a = a;this.b = b;this.c = c;function f(){d++;console.log(d);}this.g = f;}var test1 = new Test();test1.g();test1.g();var test2 = new Test();test2.g();
// 练习题三var x = 1,y = z = 0;function add(n){return n = n + 1;}y = add(x); // 4function add(n){return n = n + 3;}z = add(x); // 4console.log(x, y, z);
七、面试题
function foo1(x){console.log(arguments);return x;}foo1(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]// 函数声明不能跟执行符号,只有表达式才可以跟执行符号function foo2(x){console.log(arguments);return x;}(1, 2, 3, 4, 5); // 后面的小括号传值了,当做匿名函数来处理,会忽略掉函数名;最后的小括号会被当做括号运算符,此函数不会被执行(function foo3(x){console.log(arguments);return x;})(1, 2, 3, 4, 5); // [1, 2, 3, 4, 5]
阿里面试题
function b(x, y, a){a = 10;console.log(arguments[2]);}b(1, 2, 3);
function b(x, y, a){arguments[2] = 10;console.log(a);}b(1, 2, 3);
八、ASCII码表和UNICODE码
ASCII码表:分为表一 0~127 表二:128~255;大小都是一个字节 byte
- UNICODE码:涵盖ASCII码表0~255,后255之后的字节大小为二个字节 byte
str.charCodeAt(字符串下标);
// ASCII码表:分为表一 0~127 表二:128~255;大小都是一个字节 byte// UNICODE码:涵盖ASCII码表0~255,后255之后的字节大小为二个字节 bytevar str = 'abc';var pos = str.charCodeAt(1);console.log(pos); // 98
九、作业
写一个函数,接收任意一个字符串,算出这个字符串的总字节数
// 课时九作业// 写一个函数,接收任意一个字符串,算出这个字符串的总字节数function getBytes(str){var bytes = 0;for(var i = 0; i < str.length; i++){var pos = str.charCodeAt(i);if(pos <= 255){bytes++;}else{bytes+=2;}}return bytes;}console.log(getBytes('你好,世界!Hello World!'));// 课时九作业// 写一个函数,接收任意一个字符串,算出这个字符串的总字节数function getBytes(str){var bytes = str.length;for(var i = 0; i < str.length; i++){var pos = str.charCodeAt(i);if(pos > 255){bytes++;}}return bytes;}
