zoukankan      html  css  js  c++  java
  • js 学习笔记 -- js基础知识

    js

    变量,类型,计算

    类型

    值类型:字符串,数字,bool,Symbol

    引用类型:object,array,function,null

    typeof运算符

    typeof能识别所有值类型,识别函数,判断是否是引用类型(不可再细分)

    拷贝

    1. 浅拷贝 -- 改变拷贝对象的值,原值改变
    2. 深拷贝 -- 改变拷贝对象的值,原值不改变

    如何实现深拷贝:

    • 判断是值类型还是引用类型
    • 判断是数组还是对象
    • 递归

    判断和计算

    运算符:

    当加号运算符时,String和其他类型时,其他类型都会转为 String;其他情况,都转化为Number类型 , 注: undefined 转化为Number是 为’NaN‘, 任何Number与NaN相加都为NaN。
    其他运算符时, 基本类型都转换为 Number,String类型的带有字符的比如: '1a' ,'a1' 转化为 NaN 与undefined 一样。

    当object与基本类型,Number类型会先调用valueOf(), String类型会先调用toString(), 如果结果是原始值,则返回原始值,否则继续用toString 或 valueOf(),继续计算,如果结果还不是原始值,则抛出一个类型错误

    布尔转化:

    !!完全等同于Boolean()

    除了 == null之外,其他都一律用 ===

    类型比较:

    如图所示:
    对象和布尔值进行比较时,对象先转换为字符串,然后再转换为数字,布尔值直接转换为数字
    对象和字符串进行比较时,对象转换为字符串,然后两者进行比较。
    对象和数字进行比较时,对象先转换为字符串,然后转换为数字,再和数字进行比较。
    字符串和数字进行比较时,字符串转换成数字,二者再比较。
    字符串和布尔值进行比较时,二者全部转换成数值再比较。
    布尔值和数字进行比较时,布尔转换为数字,二者比较。

    原型和原型链

    类和继承

    
    class people {
        name;
        constructor(name){
            this.name = name
        }
        say() {
            console.log(this.name)
        }
    }
    
    class student extends people{
        age;
        constructor(name,age){
            super(name)
            this.age = age
        }
        say() {
            console.log(this.age)
        }
    }
    
    let a = new student("chuck",10)
    a.say()
    console.log(a.name)
    console.log(a.__proto__.name)
    
    

    原型链

    • 关系

    每个 class 都有显式原型 prototype
    每个实例都有隐式原型 proto
    实例的 proto 指向对应 class 的 prototype

    • 基于原型的执行规则

    对象的成员查找机制依靠原型链:当访问一个对象的属性(或方法)时,首先查找这个对象自身有没有该属性;如果没有就找它的原型;如果还没有就找原型对象的原型;以此类推一直找到null为止,此时返回undefined。__proto__属性为查找机制提供了一条路线,一个方向。

    new在执行时做了什么:

    1.在内存中创建一个新的空对象实例;
    2.将对象实例的__proto__属性指向构造函数的原型对象实例;
    3.让构造函数里的this指向这个新的对象实例;
    4.执行构造函数里的代码,给这个新对象添加成员,最后返回这个新对象。

    类型判断 instanceof

    A instanceof B成立的条件为

    左边A的隐式__proto__链上能找到一个等于右边B的显式prototype则为true,否则为false

    继承

    ES6之前常用

    原型对象+构造函数组合

    function Person(uname, age) {
        this.uname = uname;
        this.age = age;
    }
    Person.prototype.say = function() {
        return '我叫' + this.uname + ',今年' + this.age + '岁。';
    };
    function Student(uname, age, grade) {
        Person.call(this, uname, age); // 构造函数调用父类
        this.grade = grade;
    }
    Student.prototype = Object.create(Person.prototype); // 原型类对象指向父类
    Student.prototype.constructor = Student; //别忘了把constructor指回来
    
    Student.prototype.exam = function() {
        console.log('正在考试!');
    };
    Student.prototype.say = function() {
        return Person.prototype.say.call(this) + this.grade + '学生。';
    };
    var stu = new Student('张三', 16, '高一');
    console.log(stu.say()); //输出:我叫张三,今年16岁。高一学生。
    

    1.首先在子构造函数中用call方法调用父构造函数,修改this指向,实现继承父类的实例属性;
    2.然后修改子构造函数的prototype的指向,无论是寄生组合式继承,还是组合式继承,还是我们自己探索时的修改方式,本质都是把子类的原型链挂到父构造函数的原型对象上,从而实现子类继承父类的实例方法;
    3.如果需要给子类新增实例方法,挂到子构造函数的prototype上;
    4.如果子类的实例方法需要调用父类的实例方法,通过父构造函数的原型调用,但是要更改this指向。

    核心就是原型对象+构造函数组合使用。只使用原型对象,子类无法继承父类的实例属性;只使用构造函数,又无法继承原型对象上的方法。

    ES6 之后 使用 extends 关键字来继承。

    class中,所有的属性,无论是否在contructor中指定,都会绑定到class的实例对象上

     class A {
    
     }
    
     class B extends A {
    
     }
    
     let b = new B()
     console.log(b.__proto__ === B.prototype)
     console.log(B.prototype.__proto__ == A.prototype)
    

    闭包

    闭包是作用域应用的特殊情况,有两种表现:

    1.函数作为参数被传递

    2.函数作为返回值被传递

    简单理解:当一个嵌套的内部(子)函数引用了嵌套的外部(父)函数的变量(函数)时, 就产生了闭包

    异步

    JS是单线程语言,只能同时做一件事,DOM渲染时,JS执行必须停止,JS执行时,DOM渲染也必须停止

    Promise

    Promise三种状态:pending、fulfilled、rejected

    状态变化:
    1.pending-->fulfilled(成功了)
    2.pending-->rejected(失败了)

    状态变化是不可逆的

    async/await

    1. 执行async函数,返回的是Promise对象
    2. await相当于Promise的then
    3. try...catch可捕获异常,代替了Promise的catch

    宏任务/微任务

    宏任务:setTimeout、setInterval、Ajax、I/O、UI交互事件(比如DOM事件)
    微任务:Promise回调、async/await、process.nextTick(Node独有,注册函数的优先级比Promise回调函数要高)、MutaionObserver

    微任务执行时机比宏任务要早(记住)

    注意:script全部代码、(这个是执行栈的代码,属于同步代码),包括new Promise(function(){...})里面的代码,只有then、catch回调才是微任务

    实现 Promise.All

    我们可以设置一个数组,用它来存放每个 Promise 返回的数据,当该数组的长度等于 Promise 任务的个数时,说明拿到了所有的数据,此时就可以把该数组返回出去了。
    然后又因为原生 Promise.all 返回的是一个 Promise,所以我们也需要返回一个 Promise,然后把结果数据放入 resolve 中返回出去。

    Promise.all = promises => {
    	// 返回的是一个 Promise
    	return new Promise((resolve, reject) => {
    		let dataArr = new Array(promises.length)
    		let count = 0
    
    		for (let i = 0; i < promises.length; i++) {
    			// 在 .then 中收集数据,并添加 .catch,在某一个 Promise 遇到错误随时 reject。
    			// 这样,在最外面调用 Promise.all().catch() 时也可以 catch 错误信息
    			promises[i].then(res => { addData(res, i) })
    				.catch(err => { reject({ message: err, index: i }) })
    		}
    
    		function addData(data, index) {
    			dataArr[index] = data
    			count++
    			// 如果数据收集完了,就把收集的数据 resolve 出去
    			if (count === promises.length) resolve(dataArr)
    		}
    	})
    }
    

    笔试题:

    async function async1() {
        console.log('async1 start');
        await async2();
        console.log('async1 end');
    }
     
    async function async2() {
        console.log('async2');
    }
     
    console.log('script start');
     
    setTimeout(function (){
        console.log('setTimeout');
    }, 0)
     
    async1();
     
    new Promise(function (resolve) {
        console.log('promise1');
        resolve();
        console.log("???"); // 这一句是我自己加的,目的考察大家是否知道同步代码和微任务,迷惑大家resolve()后面是否还会执行
    }).then(function() {
        console.log('promise2');
    })
     
    console.log('script end');
    
    
    从上到下,先是2个函数定义
    再打印一个script start
    看到setTimeout,里面回调函数放入宏任务队列等待执行
    接着执行async1(),打印async1 start,看到await async2(),执行后打印async2,await后面的语句相当于Promise的then回调函数,所以是微任务,console.log('async1 end')放入微任务队列
    执行new Promise,new Promise里面传的函数是同步代码,打印promise1,执行resolve(),后续触发的then回调是微任务,放入微任务队列,然后执行同步代码打印 ???
    打印script end,同步代码执行完了
    检查微任务队列,依次打印async1 end和promise2(这里指的是chrome/73+浏览器,后面会说不同)
    尝试DOM渲染(如果DOM结构有变化)
    检查宏任务队列,打印setTimeout
    检查微任务队列为空,尝试DOM渲染,检查宏任务队列为空,执行结束
    
  • 相关阅读:
    jQuery对象和DOM对象
    虚拟主机的部署(Apache)
    事件流:事件冒泡和事件捕获
    ThinkPHP
    级联下拉列表
    今日份抽自己!!!
    c++中关于输入字符数组的一些问题
    今日新知(关于递归中变量的声明)
    格子游戏(并查集)
    1.3-14大象喝水
  • 原文地址:https://www.cnblogs.com/SLchuck/p/13759036.html
Copyright © 2011-2022 走看看