javascript(2)高级

目录

补充理解

函数

回调函数

IIFE

函数中的this

分号问题

原型(prototype)

显式原型与隐式原型

原型链

属性问题

instanceof

 面试题1

面试题2

变量提升与函数提升

执行上下文


补充理解

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

如何表述a和b的关系?

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

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

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

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

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

  • 释放没有时间间隔,如在函数结束之后,内部内容就会被释放
  • 垃圾回收有时间间隔,在某一段时间由垃圾回收箱释放空间
var propName='myAge';
    var value=18;
    p[propName]=value;
    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的方法进行调用,可以让一个函数称为指定任意对象的方法进行调用
<script>
      /* 
        编写程序实现以下功能
         */
      function showInfo(age) {
        if (age < 18) {
          console.log("未成年,再等等!");
        } else if (age > 60) {
          console.log("算了吧~~~");
        } else {
          console.log("刚好");
        }
      }

      showInfo(16);
      showInfo(20);
      showInfo(65);

      function f1(){
        console.log('f1');
      }
      var f2=function(){
        console.log('f2');
      }
      f1();
      f2();


      var obj={};
      function test2(obj) {
        this.xxx='atguigu';

      }
      test2.call(obj);
      console.log(obj.xxx);
    </script>

回调函数

 什么是回调函数?

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

 常见的回调函数

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

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

IIFE

全称:Immediately-Invoked Function Expression

作用

  • 隐藏实现,一个局部,一个全局的实现
  • 不会污染外部(全局)命名空间
  • 用他来编码JS模块
<script>
        // 匿名函数自调用
        (function(){
            console.log('......')
            var a=3
            console.log(a+3);
        })()
        var a=4
        console.log(a);

        (function(){
            var a=1;
            function test(){
                console.log(++a)
            }
            window.$=function(){
                return {
                    test:test
                }
            }
        })()
        $().test();
    </script>

注意:

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

函数中的this

this是什么?

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

如何确定this的值?

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

分号问题

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

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

        })()

错误理解:

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

3是undefined,无法运行

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

        })

错误理解:

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

原型(prototype)

1.函数的prototype属性

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

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

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

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

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

<script>
        console.log(Date.prototype,typeof Date.prototype);
        // {constructor: ƒ, toString: ƒ, toDateString: ƒ, toTimeString: ƒ, toISOString: ƒ, …}
        //  object
        function Fun(){

        }
        Fun.prototype.test=function(){
            console.log('test()');
        }
        console.log(Fun.prototype);//默认指向一个空对象(没有我们的属性)
        // {test: ƒ, constructor: ƒ}
        // 当我们特地加上才会有我们的属性

        // 原型对象中有constructor,他指向函数对象
        console.log(Date.prototype.constructor===Date);//true
        console.log(Fun.prototype.constructor===Fun);//true
    </script>

显式原型与隐式原型

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

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

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

function FN(){

        }
        console.log(FN.prototype);
        var fn=new FN();
        console.log(fn.__proto__);
        console.log(FN.prototype===fn.__proto__);

        FN.prototype.test=function(){
            console.log('test()');

        }
        fn.test();

内存结构图(下方)

 总结:

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

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

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

原型链

访问一个对象的属性时

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

别名:隐式原型链

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

function FN(){
            this.test1=function(){
                console.log("test1()");
            }

        }
        FN.prototype.test2=function(){
            console.log("test2()");
        }
        var FN=new FN()
        fn.test1()
        fn.test2()
        console.log(fn.toString);
        fn.test3()

var o1=new Object();
        var o2={};

 图解:

 补充:

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

console.log(FN.prototype instanceof Object);//true
        console.log(Object.prototype instanceof Object);//false
        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. 方法一般定义在原型中,属性一般通过构造函数定义在对象本身上
function Fn(){

        }
        Fn.prototype.a='xxx';
        var fn1=new Fn()
        console.log(fn1.a,fn1);

        var fn2=new Fn()
        fn2.a='yyy'
        console.log(fn1.a);//xxx
        console.log(fn2.a);//yyy

instanceof

表达式:A instanceof B

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

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

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

案例一:

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

 案例二:

console.log(Object instanceof Function);//true
        console.log(Object instanceof Object);//true
        console.log(Function instanceof Function);//true
        console.log(Function instanceof Object);//true

        function Foo(){
            console.log(Object instanceof Foo);//true
        }

 

 面试题1

function A(){

        }
        A.prototype.n=1
        var b=new A()
        A.prototype={
            n:2,
            m:3
        }
        var c=new A
        console.log(b.n,b.m,c.n,c.m);

面试题2

       function F(){}
        Object.prototype.a=function(){
            console.log('a()');
        }
        Function.prototype.b=function(){
            console.log('b()');
        }
var f=new F()
        f.a()//a()
        // f.b()endefined
        F.a()//a()
        F.b()//b()
        console.log(f);
        console.log(Object.prototype);
        console.log(Function.prototype);

变量提升与函数提升

引入:为什么输出为undefined?

var a=3
        function fn(){
            console.log(a);
            var a=4;
        }
fn()

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

var a=3
        function fn(){
            var a;
            console.log(a);
            a=4;
        }
        fn()

1.变量声明提升

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

2.函数声明提升

  • 通过function声明的函数,在之前就可以直接调用
  • 值:函数调用(对象)
console.log(b);//undefined
        fn2();//可调用 函数提升
        fn3()//不能 变量提升

        var b=3;
        function fn2(){
            console.log('fn2()');
        }
        var fn3=function(){
            console.log('fn3()');
        }

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

答:如上代码

执行上下文

1.代码分类

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

2.全局执行上下文

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

        var a1=3
        function a2(){
            console.log('a2');
        }
        console.log(a1);//3

3.函数执行上下文

  • 在调用函数,准备执行函数体之前,创建对应的函数执行上下文对象
  • 对局部函数进行预处理
  • 形参变量==>赋值(实参)==>添加为执行上下文的属性
  • arguments==>赋值(实参列表),添加为执行上下文的属性
  • var定义的局部变量==>undefined,添加为执行上下文的属性
  • function声明的函数==>赋值(fun),添加为执行上下文的方法
  • this==>赋值(调用函数的对象)
  • 开始执行函数体代码
function fn(a1){
            console.log(a1);//3
            console.log(a2);//undefined
            a3()
            console.log(this);//window
            console.log(arguments);//伪数组

            var a2=3
            function a3(){
                console.log('a3');
            }
        }
        fn(2,3)
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值