sheep

sheep 查看完整档案

杭州编辑  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑
_ | |__ _ _ __ _ | '_ \| | | |/ _` | | |_) | |_| | (_| | |_.__/ \__,_|\__, | |___/ 该用户太懒什么也没留下

个人动态

sheep 发布了文章 · 11月3日

容易忽视的Js细节

1. 函数隶属于 Object 类型, 但 typeof functin(){} === 'function'
    function getUser(){}
    typeof getUser === 'function'
    
    不存在 function 类型 由于 javaScript 函数区别对待而返回 function,在实际编程中非常方便。
2. 函数声明和函数表达式那个先被创建
    let getUser = funnction() {}
    getName(){}
        
    由于 javaScript 内部的算法原因, 在 javaScript 初始化阶段就已经将脚本中的函数声明都给创建了
    而函数表达式是在声明一个 getUser 所赋值运算时才去创建也就是说但执行栈执行到该行代码时创建,
    所以函数声明会先被创建, 这也是为什么 可以在函数声明前调用函数的原因
3. 构造函数只能返回对象,其他类型将会被忽略
    1.
    function F(){}
    
    new F() 时将会隐式创建一个对象赋值个 this ,并操作对象, 最后隐式放回 this 
    
    2.
    function F(){
        return "Jason";
    }
    
    new F() 这里将会忽略放回值 "Jason", 返回 this 指向的对象
    
    3.
    function F() {
        return { name: 'Jason'}
        }
        
    new F() 这里将不会返回 this 所指向的对象,this 对象被覆盖, 返回的是 {naem: 'Jason'} 对象 
4.NaN 不等于任何值,包括它自己
    NaN !== NaN         true 
5.isNaN 判端 NaN 错误
    isNaN(NaN)          // true  1
    isNaN('abc')        // true  2
       
    isNaN在如上 2 的测试中分明 'abc' 是一个字符串不是 NaN 但是他会返回 true 这 javaScript 
    的一个错误,我们可以使用 Number.isNaN() 进行判端,该方法很好的判断 NaN
    
    Number.isNaN(NaN)               // true
    Number.isNaN('abc')             // false    
6. 数值计算精度丢失
    0.1 + 0.3  === 0.3    false
    其实等于 0.30000000000000004    
        
    方法一
    parsefloat((0.1+0.2).toFixed(2))
    
    方法二
    (0.2 * 1e20 + 0.3 * 1e20)/1e20
7 实例对象中的 constructor 指向构造函数本身
    functin F()
    let f = new F()
    f.constructor  === F          // true
    
    f.constructor 可构造实例
    let f2 = new f.constructor();
    f2.constructor === F        // true
8 intanceof 比较的的是元素链中的原始对象
    function f(){}
    f intanceof Object          // true
9. null 转换为 Number 为 0 , undefined 转换为 Number 是为 NaN
    +null               0
    +undefined          NaNN
10 F.call.call()到底在为谁 call, 再多的call 都会被视为 F.call()
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月25日

类型判断

typeof 类型判断
typeof 判断只能 JavaScript 中的基本类型和 Object 引用类型, 对于各种 Object 只是粗略的判断为 Object 类型, 并不会判断出对象的具体类型。所以 typeof 能判断的类型有 Number, String, Boolean, Symbol, undefined,BigInt,Object.

注: typefo null 的结果为 Object 类型的, 但实际上 null 并不是 Object类型, 它所以 Null 类型,能的到这样的结果是因为 JavaSscript typeof行为上的错误所导致的。

// 1. typeof

let symbol = Symbol()

typeof 23                       // number
typeof "Jason"                  // string
typeof true                     // boolean
typeof undefined                // undefined 
typeof symbol                   // symbol
typeof 9007199254740991n        // bigint


// 不判断对象的具体类型
typeof {}               // object
typeof []               // object
typeof new Error()      // object
typeof null             // object

typeof function(){}     // function
注: function 函数隶属于 Object 类型的 但是 typeof function 时返回的是 function 而并不是 Object,这是因为 typefo 对于 function 函数区分对待,实际不并不存在 function 类型, 这是 JavaSscript 早期的错误,但对编程非常便利。
instanceof 类型判断
instanceof 判断对象的具体类型, instanceof 是通过目标对象中原型链的 prototype 与指定类型的 prototype 进行类型检查, 只要原型链中存在指定类型的原型 prototype 就返回 true 反之 false, instanceof 没有 typeof 那么局限, 它可以对 Object 的各类对象进行具体的检查判断。
new Date() instanceof Date                              // true
new String() instanceof String                          // true
new Number() instanceof Number                          // true
new Error() instanceof Error                            // true
function(){} instanceof Function                        // true
new Map() instanceof Map                                // true
new Set() instanceof Set                                // true
new RegExp('ab+c', 'i') instanceof RegExps              // true

....
注: null 没有原型, 所以不可用此方法进行判断
Object.prototype.toString() 类型判断
各种类型或对象调用 Object.prototype.toString() 方法时将返回 [object 类型] 的字符串, 可以用来判断各种数据类型。只是返回的的字符串可能在实际的编程应用中有点不好操作, 所以需要一函数来对判断后返回的结果进行处理。
  let res= {}

  "Null Undefined String Number Boolean Function Date RegExp Error Array Object Math Class".split(" ").map(item =>{
    res["[object "+ item + "]"] = item.toLowerCase();
  })
  
    function  type(obj){
    return typeof obj === "object" || typeof obj === "function" ? res[Object.prototype.toString.call(obj)] || "object" : typeof obj;
  }
  
  // 测试
  let date = new Date();
  function f(){}
  
  
  type(date);       // date
  type(f);          // function
  type([])          // array
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月18日

发布订阅模式

发布订阅模式
class EventEmitter {
  constructor() {
     this.cache = {}
  }
  
  // 注册事件
  $on(eventType, fn) {
    // 添加事件
    this.cache[eventType] = this.cache[eventType] || [];
    this.cache[eventType].push(fn);
  }
  
  // 注销事件
  $off(eventType) {
    if(this.cache[eventType]) {
        delete this.cache[name];
    }
  }
  
  // 触发事件
  $emit(eventType) {
    if(this.cache[eventType]) {
        this.cache[eventType].forEach(handle=>{
            handle();
        })
    }
  }
}

// 测试

let eventEmitter = new EventEmitter();
function f(){
   console.log("Jason");
}
eventEmitter.$on('click' f);
eventEmitter.$emit('click');        // Jason

eventEmitter.$off('click');         // click 事件注销
eventEmitter.$emit('click');        // click 事假已不存在

查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月12日

手写 Instanceof 和 new

手写 instanceof
instanceof 检查目标对象的原型链中是否有与指定对象的原型相同的原型,
通过 === 严格等于来对于两个原型是否相等。
function myInstanceof(obj, obj2) {
    let proto = obj.__proto__;
    let prototype = obj2.prototype;
    let queue = [proto];
    // 循环 obj 原型链进行获取 __proto__ 与 prototype 对比
    while(queue.length) {
        let temp = queue.shift();
        if(temp === null) return false;
        if(temp === prototype) return true;
        queue.push(temp.__proto__);
    }
}

// 测试

myInstanceof(new Date(), Date);         // true
myInstanceof({}, Object);               // true
myInstanceof('Jason', Number);          // false
myInstanceof(23, Stirng);               // false
手写 new
思路:
    1. new F() 通过构造函数创建的对象的 __proto__ 指向构造函数的原型.
    2. F() 构造函数中的 this 指向 F()构造函数的实例对象.
function myNew(F){
    let result = {};
    let arg = Array.prototype.slice.call(arguments, 1);
    // 将实例对象的 __proto__ 指向 F.prototype
    Object.setPrototypeOf(result, F.prototype);
    // this 指向实例对象
    F.apply(result, arg);
   return result;
}

// 测试
function F(name, age) {
    this.name = name;
    this.age = age;
}

let user = myNew(F, "Jason", 23);
console.log(user.__proto__ === F.prototype);            // true
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 10月4日

this指向问题

不同开发法环境下全局环境中this指向
提示: this 的指向是在代码运行时,被动态绑定的。
  • 浏览器中下全局环境的 this 指向 window
//测试
console.log(this);      // window
  • node 中全局环境的 this 指向 global
//测试
console.log(this)       // global
  • "use strict" 严格模式下全局环境的 this 指向 undefined
"use strict"

// 测试
console.log(this)      // undefined
谁调用 this 就指向谁
  • 函数在全局环境中自行调用时函数中 this 指向全局环境中 this 指向的对象

注意: 全局环境中的函数自行调用类似于被全局环境中 this 指向的对象所调用(如:window.F())

let name = "Jason"
function getName() {
    console.log(this.name);
}

1. 浏览器中
getName()       // Jason, this -> window
// 类似于
window.getName()

3. node 环境中
getName()       // Jason, this -> global
// 类似于
global.getName()

3. 严格模式中
"use strict" 
getName()       // undefined, this -> undefined
// 类似于
undefined.getName()
  • 对象中的方法在被对象调用时 this 指向调用它的对象
let user = {
    name: "Jason",
    getName: function(){
        console.log(this);
        console.log(this.name);
    },
    obj: {
        age: 23,
        getAge: function(){
            console.log(this);
            console.log(this.age);
        }
    }

}

// 测试
user.getName()          // user Jason, this -> user
user.obj.getAge()       // obj 23, this -> obj
构造函数中的 this 指向构造函数的实例对象
function User(name, age) {
    this.name = name;
    this.age = age;
}
User.prototype.getUser = function(){
    console.log(this)
}

// 测试
let user = new  User("Jason", 23)
user.getUser();// this 指向构造函数实例, this -> user
setTimeout, setInterval 中的 this 指向全局中的 this
let F = ()=> {
    setTimeout(function(){
        console.log(this)
    },2000)
}
// 测试
F();        // window, this -> window
Class 中的 this 指向类实例的对象
class User {
    constructor(name, age) {
        this.name = name;
        this.age = age;
    }
    getUser(){
        console.log(this.name);
        console.log(this.age);
        console.log(this);
    }
}

// 测试
let user = new User("Jason", 23);
user.getUser()      // Jason 23, this -> user
箭头函数中没 this, 如果箭头函数中使用 this 的话, this 指向取决于外层对象或函数的 this 指向
setTimeout(()=>{
    console.log(this);
},3000)
// this -> windeow, 箭头函数中的 this 指向取决于 setTimeout 的 this 指向
查看原文

赞 0 收藏 0 评论 2

sheep 发布了文章 · 9月27日

防抖与节流方法

防抖
防抖是当某一个时间段内多次触发同一事件时,只执行最后一次触发的事件。其余的事件都会被清除。
function debounce(f, m) { 
    let time; 
    return function(){ 
            let arg = Array.prototype.slice.call(arguments, 1);
            if(time) { 
                clearTimeout(time); 
            } 
            time = setTimeout(function(){ 
                    f.apply(this, arg)
                    },m)
     } 
} 

// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = debounce(fun, 1000); 
window.addEventListener('scroll', test)
节流
节流是在某一个时间段内事件只能被触发一次并执行,如果想再次触发执行需等待下一个时间周期。
  • 方法一
function throttle(f, m) { 
    let status = true; 
    return function(){ 
        let arg = Array.prototype.slice.call(arguments, 1); 
        if(!status) return ; 
        status = false; 
        setTimeout(function(){ 
        f.apply(this, arg); status = true; 
        }, m) 
     }
} 
     
// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = throttle(fun, 1000); 
window.addEventListener('scroll', test);
  • 方法二
function throttle(f, m) { 
    let lastTime = 0; 
    return function () { 
        let arg = Array.prototype.slice.call(arguments, 1); 
        let newTime = Date.now(); 
        console.log(newTime - lastTime); 
        if (newTime - lastTime > m) { 
            setTimeout(function () { 
                f.apply(this, arg); }, m); 
        } 
       lastTime = newTime; 
   }; 
}
                
// 测试 
function fun(){ 
    console.log("防抖"); 
} 
let test = throttle(fun, 1000);
window.addEventListener('scroll', test);
总结
  • 防抖只执行最后一次触发的事件
  • 节流只执行时间周期内第一次触发的事件
  • 防抖在时间段内触发多次函数事件,但会被清除只保留最后一次,并执行
  • 节流在时间段内只能触发执行一次事件,如果想再次触发执行将等到下一个时间周期
查看原文

赞 0 收藏 0 评论 0

sheep 发布了文章 · 9月27日

手写 call , apply, bind 方法

手写call方法
手写call思路:对象通过 Object.attributes 来访问它的属性.这时给对象添加一个属性,该属性指向需要绑定对象的函数。
通过Object.attributes去调用函数,函数中的this 指向了调用它的对象Object. 最后将属性从对象中移除。
    1. object.f = this
    2. object.f()
    3. delete object.f;
Function.prototype.myCall = function(context) {
   const self = context || window;
   let arg = Array.prototype.slice.call(arguments,1)
   self.f = this;
   self.f(...arg);
   delete self.f;
}

// 测试
function getUser(age){
    console.log(this.name);
    console.log(age)
}
let user = {    
      name: 'Jason'
}
getUser.myCall(user,24)
  • argument类数组转换为数组的方法
//方法一 
let arg = Array.prototype.slice.call(argment,1)
//方法二 
let arg = Array.prototype.concat.apply([],arguments)
//方法三 
let arg = Array.from(arguments)
// 方法四
let arg = [...arguments]
  • ...展开语法传递参数
Function.prototype.myCall = function(context, ...item) {
   const self = context || window;
   self.f = this;
   self.f(...item);
   delete self.f;
}

// 测试
function getUser(age){
   console.log(this.name);
   console.log(age);
}
let user = {    
      name: 'Jason'
}
getUser.myCall(user,24)

如上代码中的 const self = this || window 是用指定传入的对象为null时,默认为window对象

手写apply方法
apply与call的实现方式相同,apply只能出入两个参数, 第一个参数为绑定的this对象,第二个参数为一个数组,作为函数的参数。
Function.prototype.myApply = function(context, arr) {
    const self = context || window;
    if(!Array.isArray(arr)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...arr);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)

*arguments 实现apply可传递多个参数(其实的是一个伪数组对象)

Function.prototype.myApply = function(context) {
    const self = context || window;
    let arg = Array.prototype.slice.call(arguments,1)
    if(!Array.isArray(arg)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...arg);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)
  • ...展开语法实现apply传递多个参数(其实传入了一个数组)
Function.prototype.myApply = function(context,...item) {
    const self = context || window;
    if(!Array.isArray(item)){
      throw new TypeError("传入的参数类型不正确,传入一个数组");
    }
     self.f = this;
     self.f(...item);
     delete self.f;
}

// 测试
function getAge(age){
    console.log(age)
}
getAge.myApply(null, 24)
手写bind方法
bind与call,apply 不同在于函数执行后将创建一个新函数返回。bind函数可传入两个参数,第一个参数this绑定的对象,
第二个参数是一个数组或者类数组对象,第二个参数将作为实参在新函数执行时被传入。
Function.prototype.myBind = function(context){
    const obj = context || window;
    const self = this;
    let arg = Array.prototype.slice.call(arguments, 1);
    return function(){
        let arg2 = Array.prototype.slice.call(arguments, 1);
        self.apply(obj, arg.concat(arg2));
    }
}
如上mybind创建的新函数作为普通函数调用时this指向你所绑定的对象。当做为构造函数通过new去创建实例对象时this绑定的对象就
会被忽略了。因为构造函数中的会隐式创建一个实例对象,this指向这个实例对象。而不再是指向你所指定的对象。
Function.prototype.myBind = function(context){
    const obj = context || window;
    const self = this;
    let arg = Array.prototype.slice.call(arguments, 1);
    const newFun = function(){
        let arg2 = Array.prototype.slice.call(arguments, 1);
        if(this instanceof newFun) {
            self.apply(this, arg.concat(arg2));
        } else {
            self.apply(obj, arg~~~~.concat(arg2));
        }
    }
    
    //支持 new 创建对象时,实例__proto__指向绑定对象函数的prototype
    newFun.prototype = this.prototype
    return newFun;
}

// 测试
let user = {
        name: 'Jason',
        age: 23,
}
function Fun(school) {
    this.school = school;
    console.log(this.name);
    console.log(this.age);
    console.log(this.school);
}
let fun = Fun.myBind(user, '江南大学');
//  this -> user
fun()

// this -> 对象实例
let obj = new  fun();
console.log(obj.__proto__ === Fun.prototype) // ture
查看原文

赞 0 收藏 0 评论 0

sheep 关注了专栏 · 9月25日

终身学习者

我要先坚持分享20年,大家来一起见证吧。

关注 41327

sheep 关注了专栏 · 9月25日

SegmentFault 行业快讯

第一时间为开发者提供行业相关的实时热点资讯

关注 27987

sheep 关注了专栏 · 9月25日

疯狂的技术宅

本专栏文章首发于公众号:前端先锋 。

关注 24624

sheep 关注了专栏 · 9月25日

前端下午茶公众号

你不能把这个世界,让给你鄙视的人

关注 1515

sheep 关注了专栏 · 9月25日

前端食堂

个人公众号:前端食堂 你的前端食堂,记得按时吃饭~

关注 2661

sheep 关注了标签 · 9月25日

javascript

JavaScript 是一门弱类型的动态脚本语言,支持多种编程范式,包括面向对象和函数式编程,被广泛用于 Web 开发。

一般来说,完整的JavaScript包括以下几个部分:

  • ECMAScript,描述了该语言的语法和基本对象
  • 文档对象模型(DOM),描述处理网页内容的方法和接口
  • 浏览器对象模型(BOM),描述与浏览器进行交互的方法和接口

它的基本特点如下:

  • 是一种解释性脚本语言(代码不进行预编译)。
  • 主要用来向HTML页面添加交互行为。
  • 可以直接嵌入HTML页面,但写成单独的js文件有利于结构和行为的分离。

JavaScript常用来完成以下任务:

  • 嵌入动态文本于HTML页面
  • 对浏览器事件作出响应
  • 读写HTML元素
  • 在数据被提交到服务器之前验证数据
  • 检测访客的浏览器信息

《 Javascript 优点在整个语言中占多大比例?

关注 138124

sheep 关注了标签 · 9月25日

linux

Linux是一种自由和开放源代码的类Unix计算机操作系统。目前存在着许多不同的Linux,但它们全都使用了Linux内核。Linux可安装在各种各样的计算机硬件设备,从手机、平板电脑、路由器和视频游戏控制台,到台式计算机,大型机和超级计算机。

Linux家族家谱图,很全很强大!! 图中可以清楚的看出各个Linux发行版的血缘关系。无水印原图:http://url.cn/5ONhQb

关注 66717

sheep 关注了标签 · 9月25日

mysql

MySQL是一个小型关系型数据库管理系统,开发者为瑞典MySQL AB公司。在2008年1月16号被Sun公司收购。而2009年,SUN又被Oracle收购。MySQL是一种关联数据库管理系统,关联数据库将数据保存在不同的表中,而不是将所有数据放在一个大仓库内。这样就增加了速度并提高了灵活性。MySQL的SQL“结构化查询语言”。SQL是用于访问数据库的最常用标准化语言。MySQL软件采用了GPL(GNU通用公共许可证)。由于其体积小、速度快、总体拥有成本低,尤其是开放源码这一特点,许多中小型网站为了降低网站总体拥有成本而选择了MySQL作为网站数据库。

关注 64562

sheep 关注了标签 · 9月25日

springboot

Spring Boot 项目旨在简化创建产品级的 Spring 应用和服务。你可通过它来选择不同的 Spring 平台。

关注 14551

sheep 关注了标签 · 9月25日

vue.js

Reactive Components for Modern Web Interfaces.

Vue.js 是一个用于创建 web 交互界面的。其特点是

  • 简洁 HTML 模板 + JSON 数据,再创建一个 Vue 实例,就这么简单。
  • 数据驱动 自动追踪依赖的模板表达式和计算属性。
  • 组件化 用解耦、可复用的组件来构造界面。
  • 轻量 ~24kb min+gzip,无依赖。
  • 快速 精确有效的异步批量 DOM 更新。
  • 模块友好 通过 NPM 或 Bower 安装,无缝融入你的工作流。

官网:https://vuejs.org
GitHub:https://github.com/vuejs/vue

关注 100202

sheep 关注了标签 · 9月25日

程序员

一种近几十年来出现的新物种,是工业革命的产物。英文(Programmer Monkey)是一种非常特殊的、可以从事程序开发、维护的动物。一般分为程序设计猿和程序编码猿,但两者的界限并不非常清楚,都可以进行开发、维护工作,特别是在中国,而且最重要的一点,二者都是一种非常悲剧的存在。

国外的程序员节

国外的程序员节,(英语:Programmer Day,俄语:День программи́ста)是一个俄罗斯官方节日,日期是每年的第 256(0x100) 天,也就是平年的 9 月 13 日和闰年的 9 月 12 日,选择 256 是因为它是 2 的 8 次方,比 365 少的 2 的最大幂。

1024程序员节,中国程序员节

1024是2的十次方,二进制计数的基本计量单位之一。程序员(英文Programmer)是从事程序开发、维护的专业人员。程序员就像是一个个1024,以最低调、踏实、核心的功能模块搭建起这个科技世界。1GB=1024M,而1GB与1级谐音,也有一级棒的意思。

从2012年,SegmentFault 创办开始我们就从网络上引导社区的开发者,发展成中国程序员的节日 :) 计划以后每年10月24日定义为程序员节。以一个节日的形式,向通过Coding 改变世界,也以实际行动在浮躁的世界里,固执地坚持自己对于知识、技术和创新追求的程序员们表示致敬。并于之后的最为临近的周末为程序员们举行了一个盛大的狂欢派对。

2015的10月24日,我们SegmentFault 也在5个城市同时举办黑客马拉松这个特殊的形式,聚集开发者开一个编程大爬梯。

特别推荐:

【SF 黑客马拉松】:http://segmentfault.com/hacka...
【1024程序员闯关秀】小游戏,欢迎来挑战 http://segmentfault.com/game/

  • SF 开发者交流群:206236214
  • 黑客马拉松交流群:280915731
  • 开源硬件交流群:372308136
  • Android 开发者交流群:207895295
  • iOS 开发者交流群:372279630
  • 前端开发者群:174851511

欢迎开发者加入~

交流群信息


程序员相关问题集锦:

  1. 《程序员如何选择自己的第二语言》
  2. 《如何成为一名专业的程序员?》
  3. 《如何用各种编程语言书写hello world》
  4. 《程序员们最常说的谎话是什么?》
  5. 《怎么加入一个开源项目?》
  6. 《是要精于单挑,还是要善于合作?》
  7. 《来秀一下你屎一般的代码...》
  8. 《如何区分 IT 青年的“普通/文艺/二逼”属性?》
  9. 程序员必读书籍有哪些?
  10. 你经常访问的技术社区或者技术博客(IT类)有哪些?
  11. 如何一行代码弄崩你的程序?我先来一发
  12. 编程基础指的是什么?
  13. 后端零起步:学哪一种比较好?
  14. 大家都用什么键盘写代码的?

爱因斯坦

程序猿崛起

关注 114265

sheep 关注了标签 · 9月25日

前端

Web前端开发是从网页制作演变而来的,名称上有很明显的时代特征。在互联网的演化进程中,网页制作是Web 1.0时代的产物,那时网站的主要内容都是静态的,用户使用网站的行为也以浏览为主。2005年以后,互联网进入Web 2.0时代,各种类似桌面软件的Web应用大量涌现,网站的前端由此发生了翻天覆地的变化。网页不再只是承载单一的文字和图片,各种富媒体让网页的内容更加生动,网页上软件化的交互形式为用户提供了更好的使用体验,这些都是基于前端技术实现的。

Web前端优化
  1. 尽量减少HTTP请求 (Make Fewer HTTP Requests)
  2. 减少 DNS 查找 (Reduce DNS Lookups)
  3. 避免重定向 (Avoid Redirects)
  4. 使得 Ajax 可缓存 (Make Ajax Cacheable)
  5. 延迟载入组件 (Post-load Components)
  6. 预载入组件 (Preload Components)
  7. 减少 DOM 元素数量 (Reduce the Number of DOM Elements)
  8. 切分组件到多个域 (Split Components Across Domains)
  9. 最小化 iframe 的数量 (Minimize the Number of iframes)
  10. 杜绝 http 404 错误 (No 404s)

关注 156051