moyahuang / 2020Flag

2020年莫莫哒要疯狂立flag!然后疯狂拔flag!
https://moyahuang.github.io/2020Flag/
0 stars 2 forks source link

JavaScript体系结构 #3

Open moyahuang opened 4 years ago

moyahuang commented 4 years ago

类型

值类型 vs. 引用类型

考点 1. 区别

三点:存储位置,访问机制,变量间赋值不同。 前者:栈区,变量访问的是值本身,在栈区复制一份。 后者:堆区(+栈区),变量访问的是其堆区的引用对象,复制的是栈区的地址。

2. 类型判断

两个关键字+构造函数 typeof 可正确返回除null以外的值类型以及函数类型,typeof null === 'object' instanceof 可判否所有的引用类型,注意[] instanceof Array === true 且 [] instanceof Object === true constructor 对象的原型对象都有属性constructor指向其构造函数,因此也可用来判否引用类型 注:上面的方式都有其缺陷,借用Object.prototype.toString可以判断任意类型,详见下方

3. 深浅拷贝 深浅拷贝的概念是相对于引用类型存在的。 数组的浅拷贝方法:

newArr=arr.concat() //1
newArr=arr.slice() //2

对象的浅拷贝方法

function shallowCopy(obj){
    var newObj={};
    for(var attr in obj){
        if(obj.hasOwnProperty(attr)){
            newObj[attr]=obj[attr];
        }
    }
    return newObj;
}

深拷贝方法: 深拷贝可能会碰到的坑

隐式类型转换

JS有6种值类型,null, undefined, symbol比较特殊,“正常”的也就3种number, string, boolean,而类型转换的目标也就这三种类型。

注意:number类型有1种特殊值NaN

隐式类型转换的3个场景分别对应3种转换目标boolean, number, string

2种源类型:值类型和对象类型。

值类型的转换都有固定的规则,比较简单只列举特殊的几个:

转换为数字时:

对象类型的转换规则

所有的对象转换为布尔型都为true,所以需要讨论的情况是目标为number以及string

根据场景的不同,对象类型转换时所谓的hint也不同

hint='string'时,方法不存在或者返回值不为原始类型时,依次调用对象的以下方法:

[Symbol.toPrimitive]→toString→valueOf→throw Error

hint='number'和hint='default'

[Symbol.toPrimitive]→valueOf→toString→throw Error

注:

  1. default是指某些特殊情况(如+,关系运算时,无法确定转换为string还是number时,规则和number一样,不需要特殊记忆
  2. Array,Object的valueOf返回的是本身
{}==!{}//的转换过程如下
{}==false//1.
'[object Objct]'==0//2
NaN==0//3.
特殊的数学运算:关系和+

关系运算可以通过以小(弱等)见大(若不等, >, <等)的方法推导

弱等(==)
+
+"hello"//NaN
+[]//NaN
new Date+1//结果为string类型

原型和原型链

关于原型你需要知道的

  1. 对象是可扩展的,即可自由添加属性和方法
  2. 所有对象都有__proto__属性,属性值为一个普通对象,即其'原型'对象
  3. 所有函数都有prototype属性,属性值仍然是一个普通对象
  4. 函数也是对象
  5. 所有函数(包括构造函数)的__proto__指向对象Function.prototype
  6. 对象的__proto__对象指向其构造函数的prototype对象
Function.__proto__===Function.prototype;//true
Object.__proto__===Function.prototype//true
Function.prototype===Object.prototype;//因为Function.prototype也是普通对象,普通对象的构造函数即Object 第六条

所谓原型链即访问某属性和方法时,从对象本身查找,如没找到则沿着__proto__逐层查找,直到找到终点Object.prototype(Object.prototype.proto=null)。

继承

继承的核心就是将子类构造函数的原型对象设为父类的实例

注意事项:

  1. 原型对象应该有construtor属性,该属性值应指向构造函数,且该属性不可枚举
  2. 如果父类中属性值为对象类型时,子类实例对该属性的改变将会影响父类实例,这个问题可以用"借用构造函数"的方式解决
  3. 为了复用父对象方法,应该在父构造函数的原型对象上添加方法

示例

function Animal(type){
  this.type=type;
  this.sound="hello";
  this.color=['red','green','blue'];
}

Animal.prototype.sayHello=function(){
  console.log(`${this.type} say ${this.sound}`);
}

function Cat(type, sound){
  Animal.call(this, type);
  this.sound=sound;
}

Cat.prototype=new Animal();
Object.defineProperty(Cat.prototype, 'constructor', {
  value: Cat,
  enumerable: false
});

测试用例

var cat=new Cat("波斯","meow");
cat.sayHello(); // 波斯 say meow
cat.color.push('cyan'); //修改color属性值
console.log(cat.__proto__.constructor);//[Function Cat]
console.log(cat.color); //[ 'red', 'green', 'blue', 'cyan' ]

var animal=new Animal('any');
console.log(animal.color);//[ 'red', 'green', 'blue'] 

作用域和作用域链

概念:自由变量,闭包 考点

moyahuang commented 4 years ago

看懂源码必备知识点

moyahuang commented 4 years ago

跟着yayu学习JavaScript实用算法

moyahuang commented 4 years ago

手写原生方法

模拟实现一个new的效果

模拟new的效果要注意:

function create(){
    var obj=new Object();
    var constructor=[].shift.call(arguments);//获取构造函数
    obj.__proto__=constructor.prototype;
    var res=constructor.**apply**(obj, arguments);//将构造函数的属性挂在obj上
    return res instanceof Object?res:obj;
}

如何将arguments转换为数组 [].prototype.slice(arguments)

模拟实现一个 bind 的效果

实现一个 call/apply 函数

手写Promise

手写XMLHttpRequest

使用示例

var xhr=new XMLHttpRequest();

xhr.open("post","http://example.com/post", true);//false表示异步请求

xhr.onreadystatechange=function(){
    if(xhr.readystate === 4){
        if(xhr.status>=200 && xhr<300){
            alert(xhr.responseText);
        }
    }
}
var data={ name:"moya", age:13};
//模拟POST表单提交
xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");

xhr.send(transform(data)));//参数不能为空