• javascript(2)高级


    目录

    补充理解

    函数

    回调函数

    IIFE

    函数中的this

    分号问题

    原型(prototype)

    显式原型与隐式原型

    原型链

    属性问题

    instanceof

     面试题1

    面试题2

    变量提升与函数提升

    执行上下文


    补充理解

    1. var c={name:'tom'};
    2. console.log(c);
    • c本身不是对象,是变量。只是说c能找到{name:'tom'};这个对象,c这个变量保存的是内存对象的地址
    • var说明JavaScript是弱类型
    • 在运行后,先编译后解析
    • 内存怎么找?——>根据名称来找
    • 什么样的内存需要他的地址?——>内存为对象。
    • 需要c.name时,内存要有地址值数据和内存数据
    1. var a={age:12};
    2. var b=a;
    3. a={name:'bob',age:13};
    4. b.age=14;
    5. console.log(b.age,a.name,a.age);

    如何表述a和b的关系?

    • 将a的内容传给了b,内容为a的地址值
    • 从该例子可以看出,要让2个引用变量指向同一个对象,保存的是地址值
    1. var obj={age:18};
    2. function set(obj){
    3. obj={age:12};
    4. }
    5. set(obj);
    6. console.log(obj.age);

    (易错)函数执行完,内部内容会被垃圾回收(对)

    如何理解obj的内容输出没有发生改变呢?——>obj在加入函数后,堆地址改变了,但是他并没有改变之前obj里存的内容

    1. var a=3;
    2. var obj={};
    3. var obj2=null;
    • a占一个内存空间
    • obj占两个
    • obj2占一个

    区分“释放”和“垃圾回收”

    • 释放没有时间间隔,如在函数结束之后,内部内容就会被释放
    • 垃圾回收有时间间隔,在某一段时间由垃圾回收箱释放空间
    1. var propName='myAge';
    2. var value=18;
    3. p[propName]=value;
    4. console.log(p[propName]);

    如何理解变量名不确定的情况?

    对象中的[]可以理解为函数的传参,所以他可以是个字符串也可以是一个变量,因此该案例中的p[propName]等价于p.myAge

    函数

    什么是函数?

    • 实现特定功能的n条语句的封装体
    • 只有函数是可以执行的,其他类型的数据不能执行

    为什么要用函数?

    • 提高代码复用
    • 便于阅读交流

     如何定义函数?

    • 函数声明
    • 表达式

    如何调用(执行)函数?

    1. test()        直接调用
    2. obj.test()        通过对象调用
    3. new test()        new调用
    4. test.call/apply(obj)        让test称为obj的方法进行调用,可以让一个函数称为指定任意对象的方法进行调用

    回调函数

     什么是回调函数?

    1. 你定义的
    2. 你没有调
    3. 但最终执行了

     常见的回调函数

    • dom事件回调函数(与用户交互)
    • 定时器回调函数
    • ajax请求回调函数(后面讲)(与后台交互)
    • 生命周期回调函数(后面讲)

    函数分为两种,一种用于储存,一种用于执行

    IIFE

    全称:Immediately-Invoked Function Expression

    作用

    • 隐藏实现,一个局部,一个全局的实现
    • 不会污染外部(全局)命名空间
    • 用他来编码JS模块

    注意:

    1. window.$:把window对象传入这个匿名函数中,并且同时执行这个函数,在页面载入之前就执行
    2. $是一个函数
    3. $执行后返回的是一个对象

    函数中的this

    this是什么?

    • 任何函数本质上都是通过某个对象来调用的,如果没有直接指定就是window
    • 所有函数内部都有一个变量this
    • 他的值是调用函数的当前对象

    如何确定this的值?

    • test()        window
    • p.test()        p
    • new test()        新创建的对象
    • p.call(obj)        obj

    分号问题

    在以下2种情况下不加分号会有问题

    • 小括号开头的前一条语句
    • 方括号开头的前一条语句
    1. var a=3
    2. ;(function(){
    3. })()

    错误理解:

    var a=3(function(){})();

    3是undefined,无法运行

    1. var b=4
    2. ;[1,3].forEach(function(){
    3. })

    错误理解:

    1. var b=4[3].forEach(function(){
    2. })

    原型(prototype)

    1.函数的prototype属性

    每个函数都有一个prototype属性,他默认指向一个object空对象(即:原型对象)

    原型对象中有一个属性constructor,它指向函数对象

    2.给原型对象添加属性(一般都是方法)——>用于实例对象

    作用:函数的所有实例对象自动拥有原型中的属性(方法)

     上图,表明对象能找到对象原型,对象原型能找到对象,两者是相互的

    显式原型与隐式原型

    每个函数function都有一个prototype,即显式原型(属性)

    每个实例对象都有一个__proto__,可以称为隐式原型(属性)

    对象的隐式原型的值为其对应的显式原型的值

    1. function FN(){
    2. }
    3. console.log(FN.prototype);
    4. var fn=new FN();
    5. console.log(fn.__proto__);
    6. console.log(FN.prototype===fn.__proto__);
    7. FN.prototype.test=function(){
    8. console.log('test()');
    9. }
    10. fn.test();

    内存结构图(下方)

     总结:

    函数的prototype属性:在定义函数时自动添加的,默认值是一个空Object对象

    对象的__proto__属性:创建对象时自动添加的,默认值为构造函数的prototype属性值

    程序员能直接操作显式原型,但不能直接操作隐式原型(ES6之前)

    原型链

    访问一个对象的属性时

    • 先在自身属性中查找,找到返回
    • 如果没有,再沿着__proto__这条链向上查找,找到返回
    • 如果最终没有找到,返回undefined

    别名:隐式原型链

    作用:查找对象的属性,不是查找对象的变量

    1. function FN(){
    2. this.test1=function(){
    3. console.log("test1()");
    4. }
    5. }
    6. FN.prototype.test2=function(){
    7. console.log("test2()");
    8. }
    9. var FN=new FN()
    10. fn.test1()
    11. fn.test2()
    12. console.log(fn.toString);
    13. fn.test3()

    1. var o1=new Object();
    2. var o2={};

     图解:

     补充:

    函数的显式原型指向的对象默认是空Object实例对象(但Object不满足)

    1. console.log(FN.prototype instanceof Object);//true
    2. console.log(Object.prototype instanceof Object);//false
    3. console.log(Function instanceof Object);//true

    所有函数都是Function的实例(包括Function)

    console.log(Function.__proto__===Function.prototype);//true

    Object的原型对象是原型链尽头

    console.log(Object.prototype.__proto__);//null

    属性问题

    1. 读取对象的属性值时,会自动找到原型链中查找
    2. 设置对象属性值时,不会查找原型链,如果当前对象中没有此属性,直接添加此属性并设置其值
    3. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
    1. function Fn(){
    2. }
    3. Fn.prototype.a='xxx';
    4. var fn1=new Fn()
    5. console.log(fn1.a,fn1);
    6. var fn2=new Fn()
    7. fn2.a='yyy'
    8. console.log(fn1.a);//xxx
    9. console.log(fn2.a);//yyy

    instanceof

    表达式:A instanceof B

    (A为实例对象,B为构造函数)就是判断A是否为B的实例

    如果B函数的显式原型对象在A对象的原型链上,返回true,否则返回false

    Function是通过new自己产生的实例

    案例一:

    1. function Foo(){}
    2. var f1=new Foo();
    3. console.log(f1 instanceof Foo);//true
    4. console.log(f1 instanceof Object);//true

     案例二:

    1. console.log(Object instanceof Function);//true
    2. console.log(Object instanceof Object);//true
    3. console.log(Function instanceof Function);//true
    4. console.log(Function instanceof Object);//true
    5. function Foo(){
    6. console.log(Object instanceof Foo);//true
    7. }

     

     面试题1

    1. function A(){
    2. }
    3. A.prototype.n=1
    4. var b=new A()
    5. A.prototype={
    6. n:2,
    7. m:3
    8. }
    9. var c=new A
    10. console.log(b.n,b.m,c.n,c.m);

    面试题2

    1. function F(){}
    2. Object.prototype.a=function(){
    3. console.log('a()');
    4. }
    5. Function.prototype.b=function(){
    6. console.log('b()');
    7. }
    8. var f=new F()
    9. f.a()//a()
    10. // f.b()endefined
    11. F.a()//a()
    12. F.b()//b()
    13. console.log(f);
    14. console.log(Object.prototype);
    15. console.log(Function.prototype);

    变量提升与函数提升

    引入:为什么输出为undefined?

    1. var a=3
    2. function fn(){
    3. console.log(a);
    4. var a=4;
    5. }
    6. fn()

    答:实际运行时,函数体先在内部创建了a,因此在函数中找到的是当前的a,代码如下

    1. var a=3
    2. function fn(){
    3. var a;
    4. console.log(a);
    5. a=4;
    6. }
    7. fn()

    1.变量声明提升

    • 通过var定义(声明)的变量,在定义语句之前就可以访问到
    • 值:undefined

    2.函数声明提升

    • 通过function声明的函数,在之前就可以直接调用
    • 值:函数调用(对象)
    1. console.log(b);//undefined
    2. fn2();//可调用 函数提升
    3. fn3()//不能 变量提升
    4. var b=3;
    5. function fn2(){
    6. console.log('fn2()');
    7. }
    8. var fn3=function(){
    9. console.log('fn3()');
    10. }

    3.问题:两者是如何产生的?

    答:如上代码

    执行上下文

    1.代码分类

    • 全局代码
    • 函数(局部)代码

    2.全局执行上下文

    • 在执行全局代码前将window确定为全局执行上下文(虚拟的,在栈中)
    • 对全局数据进行预处理
    • var定义的全局变量==>undefined,添加为window的属性
    • function声明的全局函数==>赋值(fun),添加为window的方法
    • this==>赋值(window)
    1. console.log(a1,window.a1);//undefined undefined
    2. a2()//a2
    3. console.log(this);//window
    4. var a1=3
    5. function a2(){
    6. console.log('a2');
    7. }
    8. console.log(a1);//3

    3.函数执行上下文

    • 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
    • 对局部函数进行预处理
    • 形参变量==>赋值(实参)==>添加为执行上下文的属性
    • arguments==>赋值(实参列表),添加为执行上下文的属性
    • var定义的局部变量==>undefined,添加为执行上下文的属性
    • function声明的函数==>赋值(fun),添加为执行上下文的方法
    • this==>赋值(调用函数的对象)
    • 开始执行函数体代码
    1. function fn(a1){
    2. console.log(a1);//3
    3. console.log(a2);//undefined
    4. a3()
    5. console.log(this);//window
    6. console.log(arguments);//伪数组
    7. var a2=3
    8. function a3(){
    9. console.log('a3');
    10. }
    11. }
    12. fn(2,3)
  • 相关阅读:
    国际航运管理简答题-题库
    Jenkins 内置变量 和变量作用域
    【Spatial-Temporal Action Localization(六)】论文阅读2021年
    Synchronized代码详解?
    javaweb--jsp
    头哥的实践平台的Linux文件/目录管理
    学习Java到底要不要报班?自学可以吗?
    【软考-中级】系统集成项目管理工程师 【16 变更管理】
    Mysql 分布式序列算法
    阿里开源数据同步神器DataX异构数据源间数据同步同步MySQL与HDFS相互实战
  • 原文地址:https://blog.csdn.net/m0_62520946/article/details/126118085