JavaScript

0、一些概念

(1)JavaScript 中的所有事物都是对象:字符串、数值、数组、函数;此外,JavaScript 允许自定义对象。对象只是一种特殊的数据,对象拥有属性和方法;即对象只是带有属性和方法的特殊数据类型。

  • 布尔型可以是一个对象。数字型可以是一个对象。字符串也可以是一个对象。日期是一个对象。数学和正则表达式也是对象。数组是一个对象。甚至函数也可以是对象。
  • 请不要把字符串、数值和布尔值声明为对象!如果通过关键词 “new” 来声明 JavaScript 变量,则该变量会被创建为对象:
    var x = new String(); // 把 x 声明为 String 对象
    var y = new Number(); // 把 y 声明为 Number 对象
    var z = new Boolean(); // 把 z 声明为 Boolean 对象
    请避免字符串、数值或逻辑对象,他们会增加代码的复杂性并降低执行速度。

(2)JavaScript 是面向对象的语言,但 JavaScript 不使用类。在 JavaScript 中,不会创建类,也不会通过类来创建对象(就像在其他面向对象的语言中那样)。JavaScript 基于 prototype(原型),而不是基于类的。(函数 + prototype 机制)

  • 基于类的是创建模型,基于原型的是经验模型,前者是现有马这个概念,才有胯下之马这个实体,后者是先有胯下之马这个实体,才有马这个概念。
  • 在思考面向原型的时候,类的概念有是可以的,因为本质上对象的原型就是类。但是,类构造出对象的这个过程却要不得,面向原型里,是由具体对象推导出原型来的。
  • 访问对象的属性或者方法时,会访问其__proto__以及__proto__的__proto__,直到找到这个属性或者方法为止,而函数的prototype属性执行后会返回执行结果的__proto__。

1、apply() 方法与 call() 方法

apply() 方法能劫持另外一个对象的方法,继承另外一个对象的属性。

var person = {
    fullName: function (city, country) {
        return this.firstName + " " + this.lastName + "," + city + "," + country;
    }
}
var person1 = {
    firstName: "Bill",
    lastName: "Gates"
}
var x = person.fullName.apply(person1, ["Seatle", "USA"]);
// var x = person.fullName.call(person1, "Seatle", "USA");
// 应用输出:
Bill Gates, Seatle, USA

2、函数节流(throttle)与函数防抖(debounce)

函数节流:限制一个函数在一定时间内只能执行一次;即在一定时间之内,限制一个动作只执行一次。

// 时间戳方案
function throttle(fn, wait) {
    let pre = Date.now();
    return function () {
        let context = this;
        let args = arguments;
        let now = Date.now();
        if (now - pre >= wait) {
            fn.apply(context, args);// args 即上面的 pre,this 是为了能持有 args 
            pre = Date.now();
        }
    }
}

window.addEventListener("mousemove", throttle(fu, 1000));

函数防抖:短时间内多次触发同一事件,只执行最后一次,或者只执行最开始的一次,中间的不执行。

/**
   * @desc 函数防抖
   * @param func 目标函数
   * @param wait 延迟执行毫秒数
   * @param immediate true - 立即执行, false - 延迟执行
   */
function debounce(func, wait, immediate) {
    let timer;
    return function () {
        let context = this;
        let args = arguments;

        if (timer) clearTimeout(timer);
        if (immediate) {
            let callNow = !timer;
            timer = setTimeout(() => {
                timer = null;
            }, wait);
            if (callNow) func.apply(context, args);
        } else {
            timer = setTimeout(() => {
                func.apply(context, args);
            }, wait)
        }
    }
}

3、数组去重的n种方式

利用数组 filter 方法过滤:

Array.prototype.unique = function unique() {
    var res = this.filter(function (item, index, array) {
        return array.indexOf(item) === index;
    });
    return res;
}

利用对象属性的唯一性:

Array.prototype.unique = function () {
    var temp = [], hash = {};    // hash 作为哈希表
    for (var i = 0; i < this.length; i++) {
        if (!hash[this[i]]) {    // 如果哈希表中没有当前项
            hash[this[i]] = true;
            temp.push(this[i])
        }
    }
    return temp;
}

利用 ES6 set 数据结构:

Array.prototype.unique = function () {
    return Array.from(new Set(this));
}

运行速度差异不大,不过鉴于 set 是 ES6 新加内容,在实际开发环境中,推荐使用稳定性和速度都比较不错的前两个方法。

4、解构赋值【ECMAScript 6.0 规范(ES6)】

1、使用数组成员对变量赋值时,优先使用解构赋值:
const arr = [1, 2, 3, 4];
// bad
const first = arr[0];
const second = arr[1];
// good
const [first, second] = arr;
2、函数的参数如果是对象的成员,优先使用解构赋值:
// bad
function getFullName(user) {
  const firstName = user.firstName;
  const lastName = user.lastName;
}
// good
function getFullName(obj) {
  const { firstName, lastName } = obj;
}
// best
function getFullName({ firstName, lastName }) {
}
3TODO: 如果函数返回多个值,优先使用对象的解构赋值,而不是数组的解构赋值。这样便于以后添加返回值,以及更改返回值的顺序:
// bad
function processInput(input) {
  return [left, right, top, bottom];
}
// good
function processInput(input) {
  return { left, right, top, bottom };
}
const { left, right } = processInput(input);
for (const { name, age } of persons) {
  console.log(name);
  console.log(age);
}

5、内置函数

数值方法:

1、toFixed():可把 Number 四舍五入为指定小数位数的数字
let qqq = 1.234567;
qqq.toFixed(3); // "1.235"

2、toString():返回该数值的字符串格式
qqq.toString(); // "1.2345676"

3、valueOf():返回数值
let aaa = '1.23456789';
aaa.valueOf(); // 1.23456789

数组方法:

1、concat():返回两个数据经过联接后的数组
let arr1 = [1,2,3]
let arr2 = [3,2,1]
let arr3 = arr1.concat(arr2) // (6) [1, 2, 3, 3, 2, 1]
arr1 // (3) [1, 2, 3]
arr1 = arr1.concat(arr2)
arr1 // (6) [1, 2, 3, 3, 2, 1]
2、forEach():调用一个函数来处理数组中的每个元素。
3、map():调用一个函数处理数组中的每一个元素,将生成的结果组成一个新的数组,并返回
4、pop():返回数组中的最后一个元素,并删除
5、push():在数组的最后增加一个元素,并返回新数组的长度
6、splice():向/从数组中添加/删除项目,然后返回被删除的项目
7、sort():对数组中的元素排序。
8、reverse():反转数组元素的顺序
let arr = [1,2,3,4,5,6,7,8,9,0]
arr // (10) [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]
arr.reverse() // (10) [0, 9, 8, 7, 6, 5, 4, 3, 2, 1]

正则匹配:

1、exec 是 RegExp 类的方法:
/hello/.exec('hello world');
// JavaScript RegExp 对象  https://www.w3school.com.cn/jsref/jsref_obj_regexp.asp

2、match 是 String 类的方法:
'hello world'.match(/'hello'/);

5、get 和 set 方法

getter 是获取属性值,setter 是设置属性值,getter 不带任何参数,setter 设置键值,值以参数的形式传递,在 setter 函数体中,一切的 return 都是无效的,当只有 setter 函数时,那这个属性是只写的,当只有 getter 函数时,那这个属性是只读的,同时有 setter、getter 函数,这个属性可读可写。

let o = {
    get x() {
        return 7;
    },
    set x(val) {
        console.info("不能设置x的值");
    }
}
o.x    //7 读取x值的时候,会使用get方法
o.x = 9  //不能设置x的值 赋值x时,会使用set方法
let p = {
    get() {
        return this._p;
    },
    set(value) {
        value = value === undefined ? 0 : value;
        this._p = value;
        // 悄悄干点其它的操作
        this.xxxxx(value);
    }
}

参考:
苏格拉没有底:https://segmentfault.com/u/sugelameiyoudi_5a3a4031b8a3f/articles

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章