zoukankan      html  css  js  c++  java
  • [已读带总结] Effective JavaScript 编写高质量JavaScript代码的68个有效方法

    目录

    电子书下载:https://www.jb51.net/books/328297.html

    第2章

    第11条 熟练掌握闭包

    https://www.cnblogs.com/wengxuesong/p/5499005.html
    总结 函数传递的信息包含函数本身,和它的外层环境。(这句话是能否理解透js的根本)

    // 通用版闭包
    (function(window, undefined){})(window)
    
    // 做 leaflet 我改了一下
    (function(L, undefined){})(L)
    

    第3章 使用函数

    第18条 理解函数调用、方法调用及构造函数调用之间的不同

    https://www.cnblogs.com/wengxuesong/p/5526533.html
    简单说 function 内部的 this为父级对象。
    如果这个function在对象中,this就是这个对象。
    如果这个function在全局中,this就是window
    如果这个function是构造函数,this就是new的时候,外部包了一个对象{},this指向了这个对象。

    第19条 熟练掌握高阶函数

    https://www.cnblogs.com/wengxuesong/p/5531242.html
    高阶函数,简单说就是 function的入参或return出参是函数。
    一般情况就是 function的入参是函数,最常见的例子就是callback入参或者map some sort等函数
    函数当入参的核心含义就是把具体业务逻辑踢出去,把已确定的业务包起来。

    第20条 使用call方法自定义接收者来调用方法

    https://www.cnblogs.com/wengxuesong/p/5532254.html
    1 用函数的call方法,指定函数内的this

    function abc (a1) {
      // 这里的this指向父级
    }
    abc('a') // 函数体内指向父级,这里要是在页面就指向window
    
    var aaa = {}
    abc.call(aaa,'a') // 这个时候 aaa对象就是 abc函数的this,后面参数正常传送
    

    2 入参是个函数的时候,可以调用call,更改,入参函数的this (俗称高阶函数)

    var table = {
      fff: function (text) {
        console.info('text', text) // this指向父级
      }
    }
    
    function abc(f, objThis) {
      f.call(objThis,'a') // 这里this指向的就是objThis
    }
    
    abc(table.fff, table) // 这样fff的函数里的this,就指向 table了
    

    第21条 使用apply方法通过不同数量的参数调用函数

    https://www.cnblogs.com/wengxuesong/p/5545281.html
    apply()方法接收两个参数,一个是对象,一个是参数数组。
    apply(objThis, paramsArr) 这里的第一个参数 和 call的一样, 所以重点就是第2个参数, paramsArr,就是可变参数包成了一个数组。
    如果 apply就一个参数的话 .apply(objThis) === .call(objThis)

    arguments 是函数内接受的数组名称 举个例子

    function abc () {
      console.info('arguments', arguments)
    }
    

    ES5 bind()方法
    bind(objThis)也是接收一个参数,和call基本一样,区别是 它返回函数,并不运行。
    举例:

    var color='red';
    var o={color:'blue'};
    function sayColor(){
        console.log(this.color);
    }
    var oSayColor=sayColor.bind(o);
    oSayColor();//"blue"
    

    第22条 使用arguments创建可变参数的函数

    https://www.cnblogs.com/wengxuesong/p/5549553.html
    arguments 就是将参数 打包 变成一个数组
    几个属性
    arguments[0] 第1个参数
    arguments.length length代表参数长度。
    arguments.callee callee是一个指针指向拥有这个arguments对象的函数。
    arguments.caller caller是一个在ES3并没有定义的属性。
    callee 是指向函数,caller是谁调用的函数

    在严格模式下,arguments.callee和arguments.caller都会报错。
    ES5中arguments.caller的值始终是undefined。

    第23条 永远不要修改arguments对象

    https://www.cnblogs.com/pengchenggang/p/14764316.html

    1. 注意 arguments 并不是个真数组,他是一个对象
    2. 转化数组用 var args=[].slice.call(arguments);

    第24条 使用变量保存arguments对象

    https://www.cnblogs.com/wengxuesong/p/5553760.html
    迭代器(iterator)的小例子,里面return的时候,调用父级的arguments,直接写的话就是本级的arguments,所以可以把父级的arguments 存个变量,里面引用。
    这个类似 const _this = this 的概念,可以 const _arguments = arguments

    第25条 使用bind方法提取具有确定接收者的方法

    https://www.cnblogs.com/wengxuesong/p/5555714.html
    bind(objThis) === 绑定函数的this功能,返回当前函数

    var you={
        gF:[],
        add:function(s){
            this.gF.push(s);
        },
        all:function(){
            return this.gF.join("-");
        }
    }
    
    var girls=["西施","王昭君","貂蝉","杨贵妃"];//按人物历史出场顺序,呵呵
    girls.forEach(you.add.bind(you));
    you.all();//"西施,王昭君,貂蝉,杨贵妃"
    

    girls.forEach(you.add.bind(you)); 这里如果不用bind(you), you.add函数里面的this,在forEach就是指向forEach了。这里bind(you)后,this就是you对象,就不会错了。
    简单说,就是参数的一个反向填写的技术,正常都是 obj.abc('a'),现在这个是 ['a'].forEach(obj.abc.bind(obj))

    第26条 使用bind方法实现函数的柯里化

    https://www.cnblogs.com/wengxuesong/p/5563057.html
    什么是柯里化?

    1. 函数外包层函数。 2. 入参简化 3. 被简化的入参提供默认值

    第27条 使用闭包而不是字符串来封装代码

    https://www.cnblogs.com/wengxuesong/p/5563369.html
    1 闭包 包含父级信息 如变量 函数等
    2 字符串+eval 不包含父级信息 它的父级信息是window
    总结 字符串+eval 会污染window,并可能造成冲突,闭包优势明显

    第28条 不要信赖函数对象的toString方法

    https://www.cnblogs.com/wengxuesong/p/5567790.html
    总结 toString方法 各厂商实现不一 并且不能显示闭包代码,可参考使用。

    第29条 避免使用非标准的栈检查属性

    https://www.cnblogs.com/wengxuesong/p/5570821.html
    总结 arguments.callee 和 arguments.caller 谨慎使用,因为不一定被支持。

    第3章 使用函数--个人总结

    https://www.cnblogs.com/wengxuesong/p/5577683.html

    第4章 对象和原型

    第30条 理解prototype、getPrototypeOf和__ptoto__之间的不同

    https://www.cnblogs.com/wengxuesong/p/5580231.html
    1 prototype 是 Class类 的定义属性
    2 __proto__ 是 new后对象的 属性
    3 getPrototypeOf 是 通过new后的对象,获取 prototype

    Object.getPrototypeOf(u)===User.prototype;//true

    第31条 使用Object.getPrototypeOf函数而不要使用__proto__属性

    https://www.cnblogs.com/wengxuesong/p/5580458.html
    总结 getPrototypeOf常有 __proto__不常有

    第32条 始终不要修改__proto__属性

    https://www.cnblogs.com/wengxuesong/p/5580797.html
    总结 本来__proto__就不常有,要是再修改,结果可能无法保证。

    第33条 使构造函数与new操作符无关

    https://www.cnblogs.com/wengxuesong/p/5583089.html
    总结 构造函数内判断,如果调用者没有通过new生成对象,就自己new一个对象 return

    这里的教学意义更大一些,主要讲下单继承和多继承的算法

    第34条 在原型中存储方法

    https://www.cnblogs.com/wengxuesong/p/5584984.html

    User.prototype.checkPwd=function(pwd){
      return hash(pwd)===this.pwd;
    }
    

    prototype Class原型定义方法,new后的对象共用这个方法,不会造成内存浪费

    第35条 使用闭包存储私有数据

    https://www.cnblogs.com/wengxuesong/p/5584996.html
    总结:强调闭包中的变量为私有变量,外层访问不到。这样更具有安全性。

    第36条 只将实例状态存储在实例对象中

    https://www.cnblogs.com/wengxuesong/p/5589845.html
    总结:如果将数据放到原型中,那么数据就会共享。当new多个对象的时候,就会发生数据错乱。

    第37条 认识到this变量的隐式绑定问题

    https://www.cnblogs.com/wengxuesong/p/5589854.html
    总结:callback中的this是内部的this,不是外部的this
    解决方案1 map方法考虑周到,带了个绑定外部this的参

    lines.map(function(line){ return line.split(this.regexp); },this);
    

    解决方案2 创建self=this方法

    var self=this;
      return lines.map(function(line){
         return line.split(self.regexp);
      });
    

    解决方案3 使用.bind(this)方法

    return lines.map(function(line){
         return line.split(this.regexp);
      }.bind(this));
    

    第38条 在子类的构造函数中调用父类的构造函数

    https://www.cnblogs.com/wengxuesong/p/5592972.html

    function SpaceShip(scene,x,y){ // 子类
      Actor.call(this,scene,x,y); // 父类 注意这里没有new,用的call绑定当前子类的this为父类this
      this.points=0;
    }
    // 将父类的prototype绑定到子类上,因为构造函数运行和父类的属性是独立的
    SpaceShip.prototype=Object.create(Actor.prototype);
    

    总结 这个感觉是好古老的继承方法。但是学会了感觉很透彻。

    第39条 不要重用父类的属性名

    https://www.cnblogs.com/wengxuesong/p/5594476.html
    总结 基于上一个古老的继承方式,这个继承方式,是把父类的全部都灌到子类,这里父类拥有id属性,子类也有id属性,然后就冲突了。

    这种继承方式,就像是全局变量污染window一样,不好用,处处小心。

    第40条:避免继承标准类

    https://www.cnblogs.com/wengxuesong/p/5602793.html
    总结 继承标准类后,标准类的特殊方法不会在子类中,还要在子类重写,意义性质不大。

    第41条 将原型视为实现细节

    https://www.cnblogs.com/wengxuesong/p/5602798.html
    总结 原型方法就是公共方法,公共方法写完的就不要进行修改,修改就会出问题。A调用,改好后,B调用就可能报错。
    里面还有一句:对象是接口,原型是实现。这个类似java的 接口和实现,对此有待考究。

    第42条 避免使用轻率的猴子补丁

    https://www.cnblogs.com/wengxuesong/p/5602806.html
    猴子补丁:后期在原型上添加公共函数
    ployfill: 垫片 判断是否有此函数,如果没有,再进行赋值函数

    if(typeof Array.prototype.map!=="function"){
        Array.prototype.map=function(f,thisArg){
           var res=[];
           for(var i=0,n=this.length;i < n;i++){
             res[i]=f.call(thisArg,this[i],i);
           }
           return res;
       }
    }
    

    总结 共用的函数 就不要产生覆盖,简单说你可以用你内部的函数。

    第4章 对象和原型--个人总结

    https://www.cnblogs.com/wengxuesong/p/5602841.html

    第5章 数组和字典

    第43条 使用Object的直接实例构造轻量级的字典

    https://www.cnblogs.com/wengxuesong/p/5609493.html
    只返回对象自身的可枚举属性

    var triangle = {a:1, b:2, c:3};
     
    function ColoredTriangle() {
      this.color = "red";
    }
     
    ColoredTriangle.prototype = triangle;
     
    var obj = new ColoredTriangle();
     
    for (var prop in obj) { // 返回 所有属性 包括方法 属性 原型
      if( obj.hasOwnProperty( prop ) ) { // 不包含原型
        console.log("o." + prop + " = " + obj[prop]);
      }
    }
    // "o.color = red"
    

    总结 获取obj的包含原型的所有属性 和 obj不包含原型的所有属性

    第44条 使用null原型以防止原型污染

    https://www.cnblogs.com/wengxuesong/p/5613178.html

    var x=Object.create(null);
    Object.getPrototypeOf(x)==null;//true
    

    总结 null这个空原型很干净

    第45条 使用hasOwnProperty方法以避免原型污染

    https://www.cnblogs.com/wengxuesong/p/5613189.html

    var dict={};
    Object.prototpye.hasOwnProperty.call(dict, 'zhangsan') // false
    

    总结 直接用Object的方法,可以避免继承的子类将此方法污染,用call将那个对象,也就是this传入,就能正确调用了。

    第46条 使用数组而不要使用字典来存储有序集合

    https://www.cnblogs.com/wengxuesong/p/5619745.html
    总结 {}无序 []有序

    第47条 绝不要在Object.prototype中增加可枚举的属性

    https://www.cnblogs.com/wengxuesong/p/5619747.html
    设置不可枚举的方法

    Object.defineProperty(Object.prototype,'allKeys',{
        value:function(){
            var res=[];
            for(var key in this){
               res.push(key);
            }
            return res;
        },
        writable:true,
        enumerable:false,
        configurable:true
    });
    
    ({a:1,b:2,c:3}).allKeys();//['a','b','c']
    

    总结 Object是有定义私有函数的方法的,请大家认真对待。

    第48条:避免在枚举期间修改对象

    https://www.cnblogs.com/wengxuesong/p/5622204.html
    总结 使用for...in循环遍历对象,然后又修改这个对象。no咗no代,thx。
    这篇里主要讲解了网络的指针指向,然后遍历寻找是否包含。

    第49条:数组迭代要优先使用for循环而不是for...in循环

    https://www.cnblogs.com/wengxuesong/p/5622211.html
    总结 for(;;)遍历数组 for(in)遍历对象,for(in)会遍历出原型属性

    第50条:迭代方法优于循环

    https://www.cnblogs.com/wengxuesong/p/5626137.html
    总结 下面的请熟练使用

    Array.prototype.forEach
    Array.prototype.map
    Array.prototype.filter
    Array.prototype.some
    Array.prototype.every
    

    第51条:在类数组对象上复用通用的数组方法

    https://www.cnblogs.com/wengxuesong/p/5626364.html
    总结 arguments 就是 类数组对象
    类数组对象 看如下代码就明白了

    var arrayLike={0:'a',1:'b',2:'c',length:3};
    var res=Array.prototype.map.call(arrayLike,function(s){
        return s.toUpperCase();
    });
    res;//['A','B','C']
    

    第52条:数组字面量优于数组构造函数

    https://www.cnblogs.com/wengxuesong/p/5626367.html
    总结 数组字面量 var a=[1,2,3,5,7,8];
    数组构造函数 var a=new Array(1,2,3,5,7,8);
    []new Array好,因为Array可能会被人复写。

    这得是谁和这个代码有仇啊 复写Array

    第5章:数组和字典--个人总结

    https://www.cnblogs.com/wengxuesong/p/5628934.html

    第6章 库和API设计

    第53条:保持一致的约定

    https://www.cnblogs.com/wengxuesong/p/5633581.html
    总结 入参的两种 1 顺序 2 对象 不论哪种,大家有共识就好。

    第54条:将undefined看做“没有值”

    https://www.cnblogs.com/wengxuesong/p/5633593.html
    总结 如何获得undefined 见下面的代码

    var x; // 未赋值的变量的初始值即为undefined。
    x;//undefined
    
    var obj={}; // 访问对象不存在的属性也会产生undefined。
    obj.x;//undefined
    
    // 一个函数体结尾使用未带参数的return语句,或未使用return语句都会返回值undefined。
    function f(){ 
        return;
    }
    function g(){}
    f();//undefined
    g();//undefined
    
    // 未给函数参数提供实参则该参数的值为undefined。
    function f(x){
        return x;
    }
    f();//undefined
    

    第55条:接收关键字参数的选项对象

    https://www.cnblogs.com/wengxuesong/p/5640493.html
    总结 当函数入参较多的时候,用对象传参

    doSomething({
      sex: 'girl',
      yourName: 'Ami'
    })
    

    第56条:避免不必要的状态

    https://www.cnblogs.com/wengxuesong/p/5641325.html
    总结 无状态函数 就是 纯函数,有状态的函数 就是和内部有关联。尽量写纯函数。

    第57条:使用结构类型设计灵活的接口

    https://www.cnblogs.com/wengxuesong/p/5644673.html
    总结 面向接口编程

    var app=new Wiki(Wiki.formats.MEDIAWIKI);
    
    function Wiki(format){
        this.format=format;
    }
    
    Wiki.prototype.displayPage=function(source){
        var page=this.format(source);
        var title=page.getTitle();
        var author=page.getAuthor();
        var output=page.toHTML();
        //...
    }
    
    Wiki.formats.MEDIAWIKI=function(source){
        //....
        return {
            getTitle:function(){},
            getAuthor:function(){},
            toHTML:function(){}
        }
    };
    

    第58条:区分数组对象和类数组对象

    https://www.cnblogs.com/wengxuesong/p/5647761.html
    总结 数组对象 [{},{}] 类数组对象 {0:'1',1:'2', length:5}
    注意 类数组对象 不是数组,不能用数组方法,处理方法见51条。

    第59条:避免过度的强制转换

    https://www.cnblogs.com/wengxuesong/p/5652178.html
    总结 强制转换 会包含错误信息容差 导致后期bug不好查

    第60条:支持方法链

    https://www.cnblogs.com/wengxuesong/p/5661131.html
    总结 链式调用,就是函数最后 return this

    // 你看 var a = new String('kkk'); a.tostring() 什么意思? 数据上能带方法。。
    // 咱们 var b = new Bbb(); 最后返回的是个对象,要是显示数据 b.a 才是数据 b.c() 是方法
    // 自己new的 出来都是json 没有基本类型,但是该怎么用,还怎么用。
    
    // 特意写了个demo测试下
    function AaaClass () {
      this.k = '5'
      this.j = '6'
    }
    AaaClass.prototype.fun = function () {
      console.info('fun')
    }
    var a = new AaaClass()
    console.info('a', a)
    a.fun()
    // 输出结果
    // a AaaClass {k: "5", j: "6"}
    //    j: "6"
    //    k: "5"
    //    __proto__:
    //      fun: ƒ ()
    //      arguments:
    //      constructor: ƒ AaaClass()
    //      __proto__: Object
    // fun
    

    第6章:库和API设计--个人总结

    https://www.cnblogs.com/wengxuesong/p/5661157.html

    第7章 并发

    第61条:不要阻塞I/O事件队列

    https://www.cnblogs.com/wengxuesong/p/5674544.html
    总结 异步的时候 用 callback
    升级方案 this.$api().then()
    现在方案 const ac = this.$getAc() ac.use() ac.run()

    第62条:在异步序列中使用嵌套或命名的回调函数

    https://www.cnblogs.com/wengxuesong/p/5692711.html
    总结 这个就是 讲callback回调地狱 现在已用 $getAc 解决

    第63条:当心丢弃错误

    https://www.cnblogs.com/wengxuesong/p/5694695.html
    总结 同步错误 和 异步错误 的抓取
    同步错误 try {} catch(error) {}
    异步错误 $api('url',params).then(res=> {}, err => {})

    第64条:对异步循环使用递归

    https://www.cnblogs.com/wengxuesong/p/5710977.html
    总结 文章说 $api 调一个列表,就得是递归,现在已用 $getAc 解决该问题。

    第65条:不要在计算时阻塞事件队列

    https://www.cnblogs.com/wengxuesong/p/5713571.html
    总结 当有一个需要长时间的 大量计算的操作,可以开启个新线程去做,它有自己独立的上下文,nodejs worker-farm
    纯前台应该不会用到这块

    第66条:使用计数器来执行并行操作

    https://www.cnblogs.com/wengxuesong/p/5718098.html
    总结 $api 并发问题 现已被 axios.all(iterable) 解决

    第67条:绝不要同步地调用异步的回调函数

    https://www.cnblogs.com/wengxuesong/p/5730269.html
    总结 标题说的很明白 这是给小白的提示吧

    第68条:使用promise模式清洁异步逻辑

    https://www.cnblogs.com/wengxuesong/p/5737709.html
    总结 $api 封装的axios, 封装的promise,所以promise属于必会知识。

    第7章:并发--个人总结

    https://www.cnblogs.com/wengxuesong/p/5742503.html


    Effective JavaScript 这本书从第3章开始梳理的,前两章等有时间再看,整体的感受就是 new的前后要非常明白。new前是Class,new后是Obj。他们的基础是function。function的上下文很重要,闭包很重要。最后讲的异步部分,已封装$getAc。

    js基础决定 vue react等下一阶段的理解。

    这本书真的很不错。

    ---------------------------------------------
    生活的意义并不是与他人争高下,而在于享受努力实现目标的过程,结果是对自己行动的嘉奖。
    ↑面的话,越看越不痛快,应该这么说:

    生活的意义就是你自己知道你要做什么,明确目标。没有目标,后面都是瞎扯!
  • 相关阅读:
    Asp.Net+Oracle+BootStrap+Jquery
    UML类图几种关系的总结
    PHP对象在内存堆栈中的分配
    php sprintf 详解
    微信错误代码45047:客服消息只能发送20条/个用户
    php利用array_search与array_column实现二维数组查找
    mvc 详解
    php中++i 与 i++ 的区分详解
    Git 别名多个命令 超实用
    php 对象继承
  • 原文地址:https://www.cnblogs.com/pengchenggang/p/14764316.html
Copyright © 2011-2022 走看看