zoukankan      html  css  js  c++  java
  • something

    1.0 Object.keys()的用法

    在实际开发过程中,有时需要知道对象的所有属性,除了(for...in...)之外,原生js给我们提供了一个更优雅的方法:Object.keys(object)

    1.1 传入对象,返回包含对象可枚举属性和方法的数组

    let obj = {a:'1',b:'2'};

    console.log(Object.keys(obj));//['a','b']

    1.2 传入字符串返回索引值

    let str = 'ab';

    console.log(Object.keys(str));//['0','1']

    1.3 传入数组,返回索引值

    1.4 构造函数,返回空数组或者属性名

    function Demo(name,age){

      this.name = name;

      this.age = age;

    }

    console.log(Object.keys(Demo));//[]

    let ww = new Demo();

    console.log(Object.keys(ww));//['name','age']

    Object.keys()方法返回可枚举属性和方法的名称;若要返回可枚举和不可枚举属性和方法的名称,可以使用Object.getOwnPropertyNames()函数。

    问题描述:

    1.0 构造函数想不起来了。

    2.0 可枚举属性和不可枚举属性的区别

    2.1可枚举属性

    我们定义一个数组

    var a = [1,2,3,4,5];
    然后加一个原形方法。
    Array.prototype.order = function() {
        //排序操作
    };
    然后
    var total = null;
    for (var i in a) {
       total += a[i];
    }
    cosole.log(total); 
    结果变为了

    15function (){

    }

    原因是Array数组的原形方法也被遍历出来了,这里就涉及到js可枚举属性了。

    js中每个对象的属性都有一个试寻根叫enumerable(可枚举性),这个属性true/false 决定了该属性是都可枚举。

    (js里万物皆属性,对象的属性也是对象)

    2.2 js中那些属性可枚举,那些不可枚举?

    1.0 js基本数据类型【自带的原形属性】不可枚举.基本数据类型js中有六种数据类型,包括五种基本数据类型(Number,String,Boolean,Undefined,Null),和一种复杂数据类型(Object)。

    typeof null //object(因为null类型被当做一个空对象引用)

    2.0 通过Object。defineProperty()方法指定enumerable为false的属性不可枚举。

    2.3 js中哪些方法会访问到enumerable为true的对象属性?

    2.3.1 for..in..操作

    2.3.2 Object.keys()方法(和for  in  的区别就是Object.keys()不会返回对象原型链上的属性)

    2.3.3 JSON.stringif()方法

        回过头来看最开始的情形,你总不能要求别人把它定义的原形方法删除,这时候就要用到

      object.hasOwnProperty()方法了。

      该方法会判断一个对象是否含有指定的属性,但是会忽略从原型链上继承的属性。

    var total = null;
    for (var i in a) {
        if (a.hasOwnProperty(i)) {
            total += a[i];
        }
    }
    cosole.log(total); //15

    2.1Object.defineProperty()
    2.2Object.keys()
    2.3object.hasOwnProperty()

    3.0 Object.getOwnPropertyNames()函数的用法

    1.0 函数

    函数是由事件驱动的或者当它被调用时执行的可重复使用的代码块。

    事件驱动:js事件有鼠标事件,键盘事件,页面相关事件,表单相关事件,也就是,点击,触摸,页面关闭打开等事件发生之后在发生的事情。

    1.0 函数语法

    function 函数名(参数1,参数2,....){

      // 要执行的代码

    }

    1.1 函数的调用

    1.1.1 在html中

    function people(name.age){}

    <div onclick="people("真嘞",'18')"></div>

    重点:参数和变量必须一一对应的出现。

    1.2 带有返回值得函数

    function number(){

    var a = 5;

    return x;

    }

    既 number()的值是5;

    1.3  当然return 语句也可以用来退出函数

    function add(a,b){

      if(a>b){

        return ;

      }

      x = a+b;

    }

    上面代码就是当 a>b的时候 做到return 就退出函数了,并不会计算a+b

    知识点: 上面函数x没定义,我们把值赋给尚未声明的变量,该变量将被自动作为全局变量声明。

    1.4 函数的创建

    1.4.1 函数声明

    上面的就是函数声明

    调用的时候写在哪里都可以调用

    1.4.2 函数表达式(存储在变量中)

    let fun = function(){

      console.log(5)

    }

    fun();//这里是函数调用,必须写在函数表达式的后面

    1.4.2 构造函数

    // 函数可以自调 ,new 后面的Function 必须是大写,大写,大写

    let fun = new Function(console.log(8))

    1.4.3 js中函数是对象,是对象就有个属性方法,而call()和apply()是预定义的函数方法!

    这两个方法都是可以调用函数,两个方法的第一个参数必须是对象的本身!

    区别:apply传入的是一个参数数组,而call传入的是普通的参数

    例子 

    function add(a,b){

      return a+b;

    }

    add.call(add,10,2);// 返回20

    let myArray = [10,2];

    add.apply(add,myArray);//返回20

    1.5 js的运行机制问题;

    1.5.1 在js引擎中会优先解析var变量和function定义!在与解析完成之后从上到下逐步进行!

    1.5.2 解析var变量时,会把值存储在“”执行环境中“”,而不是去赋值,值是存储作用!

    例如:

    alert(a);//undefined

    var a = 5;

    输出undefined,意思是没有被初始化没有被赋值!,但并不是没有被定义

    1.5.3 在解析function时会把函数整体定义,这也就解释了为什么在function定义函数时

    可以先调用后声明了!其实表面上看是先调用了,其实在内部机制中第一步实行的是把

    以function方式定义的函数先声明了!

    1.6 js中函数有一个内置的对象arguments对象!

    作用是:

    1.6.1  在js中函数定义没有任何参数,调用该函数时可以传递任意参数!

    1.6.2 arguments对象是数组对象

    1.6.3 arguments对象的lenghth属性:获取函数的实参个数

    1.6.4 利用arguments对象特性,实现模拟函数的重载的效果

    // 我们可以很方便的找出数组中的最大值!

    x = findMax(1,123,156,66,88);

    function findMax(){

      var i,max = 0;

      for(i=0;i<agruments.length;i++){

      if(arguments[i]>max){

      max = arguments[i];

    }

    }

    return max

    }

    1.5 补充概念

    js代码在运行时,会分为两大部分,检查装载和执行阶段。

    检查装载阶段:会先检测代码的语法错误,进行变量、函数的声明

    执行阶段:变量的赋值、函数的嗲用等,都属于执行阶段

    1.7

    arguments.callee代表函数名,多用于递归调用

    1.8 自执行函数

    (function(){

      console.log(123)

    }())

    !function(){

      console.log(123)

    }()

    1.7 构造函数

    js 中创建对象的方式有两种,1.0是对象字面量和使用new表达式,对象字面量是一种很灵活的书写方式

    var a1 = {

    p:'ni hao',

    alertp:function(){

      alert('p')

    }

    }

    这样,就用对象字面量创建了一个对象a1,它具有一个成员变量p以及一个成员方法alertp,

    这种写法不需要定义构造函数,这种写法的缺点:每创建一个新的对象都需要写出完整的

    定义语句,不便于串讲大量相同类型的对象,不利于使用集成等高级特性。

      new 表达式是配合构造函数使用的。例如,new String('adfefs'),调用内置的String函数构造了一个字符串对象,下面我们用构造函数的方式来重新创建一个实现同样功能的对象,首先是定义构造函数,然后是调用new表达式:

      function Co(){

      this.p = "我说一个构造函数";

      this.alertP = function(){

      alert(this.p)

    }

    }

    var o2 = new Co();

    那么在使用new操作符来调用一个构造函数的时候,到底发生了什么呢,

    发生了4件事:

     1.0 let obj = {}

    2.0 obj.__proto__ = CO.prototype;

    3.0 CO.call(obj);

    4.0 return obj;

    __proto__ 和prototype (不熟悉)

    call()不熟悉 
    第一行,创建了一个空对象obj

    第二行, 将这个空对象的__proto__成员指向了构造函数对象的prototype成员对象,这是关键的一步

    第三行,将构造函数的作用域赋给新对象,因此CO函数中的this指向新对象obj,然后再调用CO函数。于是我们就给obj对象赋值了一个成员变量p,这个成员变量的值是” I’min constructed object”。

    第四行,返回新对象obj。(当构造函数里面包含返回语句时情况特殊,)

    正确定义js构造函数

       不同于其它的主流编程语言,js的构造函数并不是作为类的一个特定方法存在的;当任意一个普通函数用于创建一类对象时,它就被称作为构造函数,或构造器,一个函数要作为一个真正意义上的构造函数,需要满足以下条件:

    1. 在函数内部对新对象(this)的属性进行设置,通常是添加属性和方法。

    2. 构造函数可以包含返回语句(不推荐),但是返回值必须是this,或者其他非对象类型的值。

    上文定义的构造函数CO就是一个标准的,简单的构造函数,下面例子定义的函数C1返回了一个对象,我们可以使用new表达式来调用它,该表达式可以正确但会返回一个对象:

    function C1(){

      let o = {

        p:'i am p in C1'  

      }

    return o;

    }

    var o1 = new C1();

    alert(01.p);//i am p in C1

      注意:但是这种方式并不是值得推荐的方式,因为对象o1的原形是函数C1内部定义的对象o的原型,也就是Object.prototype,这种方式相当于执行了正常new表达式的前三步,而在第四步的时候返回了C1函数的返回值,该方式同样不便于创建大量相同类型的对象,不利于使用集成等高级特性,

    并且容易造成混乱,应该摒弃。

      一个构造函数在某些情况下完全可以作为普通的功能函数来使用,这就是js灵活性的一个体现,下例定义的C2 就是一个“多用途”函数。

    function C2(a,b){

      this.p = a +b;

      this.alertP = function(){

        alert(this.p)

      }

      return this.p;// 此返回语句在C2作为构造函数时没有意义

    }

    let c2 = new C2(2,3);

    c2.alertP();//结果为5

    alert(C2(2,3))//结果为5

    该函数既可以用作构造函数来构造一个对象,也可以作为普通的函数来使用,用作普通函数时,

    它接收两个参数,并返回两者的相加的结果,为了代码的可读性和可维护性,建议作为构造函数的

    函数不要掺杂除构造作用以外的代码,同样的,一般的功能函数不要用作构造对象。

    为什么要使用构造函数

      根据上文的定义,在表面上来看,构造函数似乎只是对一个新创建的对象进行初始化,增加一些成员变量和方法然而构造函数的作用远不止这些,为了说明使用构造函数的意义,我们看上面的

    例子 let o2 = new CO();创建对象的时候,发生了四件事:最红的是第二步

      将新生成的__prop__属性赋值为构造函数的prototype属性,使得通过构造函数创建的所有对象可以共享相同的原型。这意味着同一个构造函数创建的所有对象都集成自一个相同的对象,因此它们都是同一个类的对象。

      在js的标准中,并没有__prop__这个属性,不过它现在已经是一些主流的js执行环境默认的一个标准属性,用于指向构造函数的原型。该属性是默认不可见的,而且在各执行环境中实现的细节各不相同,例如IE浏览器中不存在该属性,我们只要知道js对象内部存在指向构造函数原型的指针就行啦,这个指针是在条用new表达式的时候自动赋值的,并且我们不应该去修改它。

      在构造对象的4个步骤中,我们可以看到,除第二步以外,别的步骤我们无须借助new表达式去实现,因此new表达式不仅仅是对这4个步骤的简化,也是要上线继承的必经之路。

    容易混淆的地方

      关于js的构造函数,有一个容易混淆的地方,那就是原型的constructor,在js中,每一个函数都有默认的原型对象属性prototype,该对象默认包含了两个成员属性:constructor和__proto__,关于原型的细节就不在本文赘述。

      按照卖你想对象的习惯性思维,我们说构造函数相当于“类”的定义,从而可能会认为constructor

    属性就是该类实际意义上的构造函数,在new表达式创建一个对象的时候,会直接调用constructor来初始化对象,那就大错特错了,new表达式执行的实际过程已经在上文中介绍过了(4个步骤),其中用于初始化对象的是第三步,调用的初始化函数正是"类函数"本身,而不是constructor,如果没有考虑过这个问题,这一点可能就不太好理解。

    那我们举例说明一下吧!

    function c3(a,b){

      this.p = a+b;

      this.alertP = function(){

      alert(this.p);  

      }

    }

    //我们定义一个函数来覆盖C3原型中的constructor,试图改变属性p的值

    function fake(){

      this.p = 100;  

    }

    C3.prototype.constructor = fake;;//覆盖C3原型中的constructor

    var c3 = new C3(2,3)

    c3.alertP();//结果仍然为5

      上述代码手动改变了C3原型中的constructor函数,然而去没有对c3对象产生实质的影响,课件new表达式中,起初始化对象作用的只能是构造函数本身,那么constructor属性的作用是什么呢?

    一般来说,我们可以使用constructor属性来测试对象的类型:

    var myArray = [1,2,3];

    (myArray.constructor == Array);//true

    这招对于简单的对象是管用的,设计到继承或者跨窗口等复杂情况时,可能就没那么灵光了:

    1. function f() { this.foo = 1;}  
    2. function s() { this.bar = 2; }  
    3. s.prototype = new f(); // s继承自f  
    4. var son = new s(); // 用构造函数s创建一个子类对象  
    5. (son.constructor == s); // false  
    6. (son.constructor == f); // true  

     这样的结果可能跟你的预期不相一致,所以使用constructor属性的时候一定要小心,或者干脆不要用它。

     

    下一节:讲解prototype和__proto__是什么和作用和区别。

      

  • 相关阅读:
    typescript 装饰器
    typescript 中的模块
    深入理解typeScript中的泛型类
    泛型 泛型类
    vue跨域
    我喜欢的网站
    vuex
    路由导航守卫
    最多显示两行
    git命令
  • 原文地址:https://www.cnblogs.com/lieaiwen/p/10136878.html
Copyright © 2011-2022 走看看