9 - 构造函数及实例化原理、包装类

24 阅读4分钟

一、构造函数

  1. 构造函数不设置返回值时,默认return this; 如果设置返回值为原始值(number、string、null...)时,也是会return this;如果设置返回值为引用值({}、[]、function...)时,那么就会出来的值就会变成引用值;
// 1. retrun 引用值({}、[]、function...)
function Car() {
  this.color = 'red';
  this.brand = 'Benz';
  return {};
}
var car1 = new Car();
console.log(car1); // {}

//打印结果:{}


// 2. return 原始值(Number、string、null...)
function Car() {
  this.color = 'red';
  this.brand = 'Benz';
  return 'str'; //等同于 return this 或者不写
}
var car1 = new Car();
console.log(car1); //Car {color: "red", brand: "Benz"}

//打印结果:Car {color: "red", brand: "Benz"}

二、包装类

  1. 三种包装类:new Number()、new String()、new Boolean()
  2. 原始值没有方法和属性,undefined、null不可以设置任何方法和属性,因为它们没有原型,而且也不能通过包装类转换为对象;
  3. 原始值(number、string、boolean)经过new Number()、new String()、new Boolean()等内置方法new出来一个实例化对象,变成一个对象之后就可以设置对象、方法

1. new Number()案例分析:

var a = 123;
a.len = 3; // 过程:new Number(123).len = 3 delete
console.log(a.len); // undefined
/**
* 思路分析:
* 1.原始值没有方法和属性,但是a是number类型,它通过系统内置的new Number()方法变成一个对象
* 2. 然后给对象里面添加属性len,并且给len赋值为3
* 3. 但是因为没有地方接住这个值,所以它又将它从内存中删除掉;
* 4. 所以访问a.len的时候,就是undefined
*/

2. new String()案例分析:

var str = 'abc'; // new String(str)
console.log(str.length); //3
/**
* 思路分析:
* 1.原始值没有方法和属性,但是str是string类型,它通过系统内置的new String()方法变成一个对象
* 2. new String()原形上length属性
* 3. 所以字符串类型可以访问length属性
*/

// 截断数组
var arr = [1, 2, 3, 4, 5];
arr.length = 3;
console.log(arr); //[1, 2, 3]

三、面试题

1. 面试题1-包装类

var name = 'hello';
name += 10; // 'hello10'
var type = typeof (name); // typeof ('hello10') -> string
if (type.length === 6) {
  type.text = 'string'; //new String(type) -> type.text = 'string' -> delete
};
console.log(type.text);

//打印结果:undefined

/**
* 思路分析:
* 1.原始值没有方法和属性,但是type是string类型,它通过系统内置的new String()方法变成一个对象
* 2. 然后给对象里面添加属性text,并且给text赋值为'string'
* 3. 但是因为没有东西接住这个值,所以它又将它从内存中删除掉;
* 4. 所以访问type.text的时候,就是undefined
*/

2. 面试题2-构造函数

//通过 new 关键字创建实例化对象,每次new 创建的对象都是不同的对象,this 指向实例化对象。

function Test(a, b, c) {
  var d = 1;
  this.a = a;
  this.b = b;
  this.c = c;
  this.f = function () {
    d++;
    console.log(d);
  }
  // return this; 形成闭包
}

// test1 和test2是不同的对象
var test1 = new Test();
var test2 = new Test();

test1.f(); // 2
test1.f(); // 3
test2.f(); // 2

3. 面试题3-函数声明提升相关

var x = 1,
    y = z = 0;

function add(n) {
  return n = n + 1;
}

y = add(x); 

function add(n) {
  return n = n + 3;
}

z = add(x);

console.log(x, y, z); // 1 4 4
//打印结果: 1  4  4

/**
 * 思路分析
 * 预编译:函数声明提升
 * GO = {
 *  x: undefined -> 1
 *  y: undefined -> 0 -> 4
 *  z: 0 -> 4
 *  add: function () { return n = n + 1 } -> function () { return n = n + 3 }
 * }
 */
// 预编译:函数声明提升,第一个函数声明被第二个函数声明覆盖
// 实际执行过程
var x = 1,
    y = z = 0; // var y; z = 0 ; y = z;
function add(n) {
  return n = n + 3;
}
y = add(x);  // 4 1+3
z = add(x);  // 4 1+3

4. 面试题4-立即执行函数相关

// 1. 函数调用并传参
function foo1(x) {
  console.log(arguments);
  return x;
}

foo(1, 2, 3, 4, 5); // 1,2,3,4,5


// 2. 函数后跟立即执行符号()
/**
* 不会执行,也不报错;
* 因为js引擎会认为这是一个函数function foo2(x) {...} + 一个表达式(1, 2, 3, 4, 5);
* 如果表达式里面不加参数就会报错,因为只有表达式才可以跟执行符号()
**/
function foo2(x) {
  console.log(arguments);
  return x;
} (1, 2, 3, 4, 5); 



// 3. 立即执行函数传参
(function foo3(x) {
  console.log(arguments);
  return x;
})(1, 2, 3, 4, 5); // 1,2,3,4,5

5. 面试题5-形参与实参的映射关系

// 映射关系
function b(x, y, a) {
  arguments[2] = 10;
  console.log(a);  // 10
}

b(1, 2, 3); //arguments[1,2,3]

//打印结果:10

四、案例

1. 写一个函数,接收任意一个字符串,返回这个字符串的总字节数

/**
* 1. charCodeAt() 方法可返回指定位置的字符的 Unicode 编码
* 2.  Unicode编码大于255的字符的字节数是1,小于255的字符的字节数是1
**/
var getBytes = function(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!')); // 12