js基础

Objects中的属性:

  • 1: Object.keys 和 Object.getOwnPropertyNames: 检索对象中所有的属性名,前一个方法返回所有可枚举的属性名,后一个方法不考虑属性的可枚举性一律返回, 但都不支持Symbol属性,ES6中增加 Object.getOwnPropertySymbols()方法来检索对象中的Symbol属性
  • 2:
//obj instanceof Array == Array[Symbol.hasInstance](obj)

function specailNumber(){}
Object.defineProperty(specailNumber,Symbol.hasInstance,{value:(v)=>(v instanceof Number) && (v >= 1 && v <= 100)})
var two = new Number(2)
    zero = new Number(0)
print(two instanceof specailNumber)
print(zero  instanceof specailNumber)
-------------------------------------------------------------------
let collection = {
    0:"hello",
    1:"world",
    length:2,
    [Symbol.isConcatSpreadable]:true
};
let message = ["HI"].concat(collection);
print(message) //[ 'HI', 'hello', 'world' ]

0 ES5 有5种类型, ES6有6种类型

  • 1: ES5: 字符串型,数字型,布尔型,null,undefined
  • 2 : ES6 + Symbol ,Symbol是原始值,因此调用new Symbol() 会报错. 但是可以 typeof symbol
  • 3: Symbol的描述被存储在内部的[[Description]]属性中,只有当调用Symbol的toString()方法时才可以读这个属性
  • 4: 所有使用可计算属性名的地方,都可以使用Symbol.Object.defineProperty()方法和Object.defineProperties()方法
  • 5: Symbol.for("uid"), 首先在全局Symbol注册表中搜索键为"uid"的Symbol是否存在,存在返回,不存在,创建新的Symbol并返回
let firstname = Symbol("firstname");
//可计算
let person = {
    [firstname]:"Nichols"
};
//将属性设置为只读
Object.defineProperty(person,firstname,{writable:false});
let lastname = Symbol("last name");
Object.defineProperties(person,{
    [lastname]:{
        value:"Zakes",
        writable:false
    }
});
print(person.firstname,person.lastname);

1 箭头函数

  • 1: 没有this,super,arguments和new.target绑定,箭头函数中的 this,super,arguments和new.target这些值由外围最近一层非箭头函数决定,
  • 2: 不能通过new关键字调用, 箭头函数没有[[]Construct]方法,所以不能作为构造函数,如果用了new就会抛出错误.
  • 3: 没有原型,由于不能通过new构造,因而没有构造原型的需求,所以箭头函数不存在prototype这个属性
  • 4: 不可以改变this的绑定,函数内部的this值不可以改变,在函数的生命周期内始终保持一致.
  • 5: 不支持 arguments对象,箭头函数没有arguments绑定,所以你必须通过明明函数和不定参数这两种形式访问函数的参数.
  • 6: 不支持重复的命名参数 无论严格参数还是非严格模式下,箭头函数都不支持重复的命名参数
  • 7: 箭头函数同样也有一个name属性,这与其他函数相同.
  • 8: 箭头函数的设计初衷是: 即用即弃, 箭头函数内的this也不能通过call apply bind来改变.但是可以在箭头函数上调用call apply bind方法,与其他函数不同,箭头函数的this值不会受这些方法的影响
var sum = (num1,num2) => num1+num2;
print(sum.call(null,1,2))
print(sum.apply(null,[1,2]))
var boundSum = sum.bind(null,1,2)
print(boundSum())

2 ES6中尾递归优化: 满足以下条件,尾调用不再创建新的栈帧,而是清除并重用当前栈帧

  • 1: 尾调用不访问当前栈帧的变量(也就是说函数不是一个闭包)
  • 2: 在函数内部,尾调用是最后一条语句
  • 3: 尾调用的结果作为函数值返回

3: js中的对象 普通对象 特异对象 标准对象 内建对象

  • 1: 普通对象(ordinary): 具有js对象所有的默认内部行为
  • 2: 特异对象(exotic) 具有某些与默认行为不符的内部行为
  • 3: 标准对象: ES6规范中定义的对象.Array Date等
  • 4: 内建对象: 脚本开始执行时存在于js执行环境中的对象,所有标准对象都是内建对象.

4: Object.assign and 自有属性的枚举顺序

  • 1: 所有数字按升序排序
  • 2: 所有字符串键按照他们被加入对象的顺序排序
  • 3: 所有symbol键按照他们被加入对象的顺序排序
var obj = {
    a:1,
    0:1,
    c:1,
    2:1,
    b:1,
    1:1
};
obj.d = 1;
print(Object.getOwnPropertyNames(obj).join("")) //012acbd

5: 改变对象的原型 Object.setPrototypeof()

let person = {
    getGreeting(){
        return "hello";
    }
}
let dog = {
    getGreeting(){
        return "woof!";
    }
}
//person prototype
let friend = Object.create(person);
print(friend.getGreeting()); //hello
print(Object.getPrototypeOf(friend) == person); //true
//set prototypeOf dog
Object.setPrototypeOf(friend,dog);
print(friend.getGreeting()) //woof!
print(Object.getPrototypeOf(friend) == dog); //true

6: 简化原型访问的super引用,必须在简写方法的对象中使用Super引用

let person = {
    getGreeting(){
        return "hello";
    }
}
let dog = {
    getGreeting(){
        return "woof!";
    }
}
let friend = {
    getGreeting(){
        //return Object.getPrototypeOf(this).getGreeting.call(this) +" hi!";
        return super.getGreeting() +" hi!";
    }
}

Object.setPrototypeOf(friend,person);
print(friend.getGreeting())
print(Object.getPrototypeOf(friend) === person)

Object.setPrototypeOf(friend,dog);
print(friend.getGreeting())
print(Object.getPrototypeOf(friend) == dog)

7: 使用var let const解构声明变量,则必须提供初始化程序.

  • 1: 如果不使用解构功能,则var let声明不强求提供初始化程序,但是const需要
  • 2: 任何解构表达式尝试读取 null or undefined的属性时都是报错.
  • 3: 读取type的属性并将其存储在变量localType中,let {type:localType,name:localName} = node
  • 4: 可以嵌套读取
let node = {
    type:"Identity",
    name:"foo",
    loc:{
        start:{
            line:1,
            column:1
        },
        end:{
            line:2,
            column:2
        }
    }
}
let {loc :{end}} = node ;
print(end.line,end.column)
let a = 1,
    b = 2 ;
[a,b] = [b,a]
print(a,b) //交换 a,b的值

// 复制数组
let colors = ["red","green","blue"];
let [...clone] = colors
print(clone)
print(colors.join(" "))
print(colors.concat(" "))

//应用场景1
function setCookie(name,value,{secure,path,domain,expire} = {}) //使用解构的话比较清晰

// ES6 之前的模拟 set and map 
var set = Object.create(null);
set.foo = true 
if(set.foo){
    print("hello")
}
var map = Object.create(null)
map.foo = "bar";
print(map.foo)

// 若引用set, 集合中的弱引用如果是对象的唯一引用,则会被回收并且释放相应内存(不支持原始值,只支持引用类型)

let set = new WeakSet(),
    key = {};
set.add(key);
print(set.has(key)); //true
set.delete(key);
print(set.has(key)); //false
//注意weakset: 不可迭代即不可以使用for..in (2)不能不报露任何迭代器例如keys and values (3)不支持forEach (4) 不支持size属性

// set and map底层都是Object.is判断相等的
 let map = new Map();
map.set("title","Understanding js");
map.set("year",2016)
print(map.get("year"))
print(map.get("title"))
//默认初始化
let map = new Map([["title","Understanding js"],["year",2016]]);
//迭代map (value,key,ownermap) => print ... 
map.forEach((v,k) => print(k+" -> "+v))
//使用weak map 存储私有数据
let Person = (function(){
    let privateDate = new WeakMap();
    function Person(name){
        privateDate.set(this,{name:name});
    }
    Person.prototype.getName = function(){
        return privateDate.get(this).name;
    };
    return Person;
}());
var p1 = new Person("shen");
var p2 = new Person("yang");
print(p1.getName())
print(p2.getName())

//新的迭代器: for ..of 循环,展开运算符(...) ,异步编程也可以使用迭代器

//ES5中写迭代器的写法, ES6中增加了 一个生成器对象,他可以让创建迭代器对象变得简单
function createIter(items){
    var i = 0;
    return {
        next : function(){
            var done = (i>=items.length);
            var value = !done ? items[i++] : undefined;
            return {done:done,value:value};
        }
    }
}
var iter = createIter([1,2,3])
print(iter.next())
print(iter.next())
print(iter.next())
print(iter.next())

//生成器是一种返回迭代器的函数,通过function*来表示,函数中会用到新的关键字yield
function*createIter(){
    yield 1;
    yield 2;
    yield 3;
}
function*createIter(items){
    for(let i = 0;i<items.length;i++){
        yield items[i];
    }
}

var iter = createIter([1,2,3])
print(iter.next())
print(iter.next())
print(iter.next())
print(iter.next())
//生成器对象的方法,
let o = {
    *createIter(items){
        for(let i =0;i<items.length;i++){
            yield items[i];
        }
    }
}
let iter = o.createIter([1,2,3])
print(iter.next())
print(iter.next())
print(iter.next())
print(iter.next())

//由于生成器默认会为Symbol.iterator属性赋值,因此所有通过生成器创建的迭代器都是可迭代对象
//for-of 循环每执行一次都会调用可迭代对象的next方法
//访问默认迭代器
let values = [1,2,3]
let iter = values[Symbol.iterator]();
print(iter.next())
print(iter.next())
print(iter.next())
print(iter.next())
//检测对象是否可迭代

//默认开发者定义的对象都是不可迭代对象,但如果给Symbol.iterator属性添加一个生成器,者可以变成一个迭代对象
let collection = {
    items:[],
    *[Symbol.iterator](){
        for(let item of this.items){
            yield item;
        }
    }
}
collection.items.push(1);
collection.items.push(2);
collection.items.push(3);

for(let x of collection){
    print(x)
}

// 内建迭代器: entries() values() keys()
let data = new Map([["title","understanding ES6"],["format","ebook"]]);
for(let [key,value] of data){
    print(key+" -> "+value);
}

//第二次调用next()方法传入的值为4,他会被赋值给变量first,函数继续执行
function *createIter(){
    let first = yield 1;
    let second = yield first + 2;
    yield second + 3;
}
let iter = createIter();
print(iter.next());
print(iter.next(4));
print(iter.next(5));
print(iter.next());

//yield语句也可以抛出异常
function *createIter(){
    let first = yield 1;
    let second;
    try{
        second = yield first + 2;
    }catch(ex){
        second = 6;
    }
    yield second +3;
}
let iter = createIter();
print(iter.next())   // { value: 1, done: false }
print(iter.next(4)) // { value: 6, done: false }
print(iter.throw(new Error("Boom!")))  //{ value: 9, done: false }
print(iter.next()) //{ value: undefined, done: true }

// yield  遇到 return 也会提前返回

// 在某些情况下,需要两个迭代器合二为一,这时可以创建一个生成器,再给yield语句添加一个星号,就可以将生成数据的过程委托给其他生成器.
function *createNumber(){
    yield 1;
    yield 2;
}
function *createColor(){
    yield "red";
    yield "green";
}
function *createCombinIter(){
    yield *createNumber();
    yield *createColor();
    yield true;
}
var iter = createCombinIter();
print(iter.next()) //{ value: 1, done: false }
print(iter.next()) //{ value: 2, done: false }
print(iter.next())//{ value: 'red', done: false }
print(iter.next())//{ value: 'green', done: false }
print(iter.next())//{ value: true, done: false }
print(iter.next())//{ value: undefined, done: true }

//简单任务执行器: 由于执行yield语句会暂停当前函数的执行过程并等待下一次调用next()方法,因此可以创建一个函数,在函数中调用生成器生成相应的迭代器,从而在不用回调函数的基础上实现异步调用next方法

function run(taskDef){
    //创建一个无使用限制的迭代器
    let task = taskDef();
    let result = task.next();
    //循环调用next函数
    function step(){
        //如果任务没完成,则继续完成
        if(!result.done){
            result = task.next()
            step()
        }
    }
    //开始迭代
    step();
}
run(function*(){
    print("1...");
    yield;
    print("2 ...");
    yield;
    print("3 ... ");
});

//任务执行器之间互相通信
function run(taskDef){
    //创建一个无使用限制的迭代器
    let task = taskDef();
    let result = task.next();
    //循环调用next函数
    function step(){
        //如果任务没完成,则继续完成
        if(!result.done){
            result = task.next(result.value)
            step()
        }
    }
    //开始迭代
    step();
}
run(function*(){
    let value = yield 1;
    print("value: "+value); // 1
    value = yield value + 3 
    print("value: "+value) // 4

//如果result.value是一个函数
function run(taskDef){
    //创建一个无使用限制的迭代器
    let task = taskDef();
    let result = task.next();
    //循环调用next函数
    function step(){
        //如果任务没完成,则继续完成
        if(!result.done){
            if(typeof result.value == "function"){
                result.value(function(err,data){
                    if(err){
                        result = task.throw(err);
                        return;
                    }
                    result = task.next(data);
                    step();
                })
            }else{
                result = task.next(result.value);
                step();
            }
        }
    }
    //开始迭代
    step();
}
let fs = require("fs");
function readFile(filename){
    return function(callback){
        fs.readFile(filename,callback);
    };
}


run(function*(){
   let contents = yield readFile("data.txt");
   print(String(contents));
   print("Done");

});

上一篇:C#编程-65:数据库Command对象复习笔记


下一篇:《Web测试囧事》——2.4 基础代码的改动影响到了其他相关产品,造成程序出错