ES6: 迭代器与生成器

什么是迭代器?

迭代器是一个对象,它拥有一个next方法,调用next方法会返回一个对象,该对象有两个属性值,value和done。每次调用next方法,返回的value表示可迭代对象中的下一个值,done表示迭代是否完成。根据此定义,可用下面的代码实现一个迭代器:

 
 
let create_iter = function(items) {
    let i = 0;
    return {
        next: function() {
            let value, done;
            if (i >= items.length) {
                value = null;
                done = true;
            } else {
                value = items[i++];
                done = false;
            }
            return {
                value: value,
                done: done
            }
        }
    }
}

什么是生成器?

用来创建迭代器的函数称之为生成器,ES6为了简化生成器,引入了新的语法:

  • 在生成器函数前加*
  • 使用yield关键字抛出下一个value

引入新的语法后,生成器的代码可以简化为:

 
 
let gen = function*(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
}

举个栗子

下面的代码比较了两种创建迭代器的方法:

 
 
let create_iter = function(items) {
    let i = 0;
    return {
        next: function() {
            let value, done;
            if (i >= items.length) {
                value = null;
                done = true;
            } else {
                value = items[i++];
                done = false;
            }
            return {
                value: value,
                done: done
            }
        }
    }
}
let gen = function*(items) {
    for (let i = 0; i < items.length; i++) {
        yield items[i];
    }
}
let items = [1, 2, 3, 4, 5];
let it = gen(items);
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());
console.log(it.next());

输出结果:

 
 
$ node test.js 
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
{ value: 5, done: false }
{ value: undefined, done: true }
{ value: undefined, done: true }

生成器的表现形式

  • function *my_generator(items) {}
  • let my_generator = function *(items) {}
  • let obj = {*my_generator(items){}};

可迭代对象

可迭代对象指的是包含Symbol.iterator属性的对象,数组、Set、Map、字符串都是可迭代对象,都有默认的迭代器。

可迭代对象可以与for-of配合使用,例如:

 
 
let numbers = [1, 2, 3, 4, 5];
for (let num of numbers) {
    console.log(num);
}

可以用一下方法自定义一个可迭代对象:

 
 
let colors = {
    items: [1, 2, 3, 4, 5],
    *[Symbol.iterator]() {
        for (let item of this.items) {
            yield item;
        }
    }
}

内置迭代器

数组、Map和Set 都有一下三个内置的迭代器:

  • entries(): 返回一个包含键值对(数组)的迭代器
  • values(): 返回一个只包含值的迭代器
  • keys(): 返回一个只包含键的迭代器

对于数组来说,keys返回的是元素的下标,对于Set来说,返回的是元素的值,而对于Map来说,返回的是元素的key。

给迭代器传入参数

当调用next方法时,若传入参数,则该参数会替代上一次yield表达式的值,例如:

 
 
let gen = function *() {
    let a = yield 1;
    let b = yield a + 1;
    yield b + 1;
}
let iter = gen();
console.log(iter.next());
console.log(iter.next(100));
console.log(iter.next(200));
console.log(iter.next());

执行结果:

 
 
$ node test.js 
{ value: 1, done: false }
{ value: 101, done: false }
{ value: 201, done: false }
{ value: undefined, done: true }

ES6: Set 与 Map

Set

  • let my_set = new Set();
  • let my_set = new Set([1, 1, 2, 2]);
  • my_set.add(5);
  • my_set.delete(5);
  • my_set.has(5);
  • my_set.forEach(function(value){});
  • let my_set = WeakSet() // 只允许对象作为set的元素,便于垃圾回收

Map

  • let my_map = new Map();
  • let map = new Map([[“name”, “Nicholas”], [“age”, 25]]);
  • my_map.set(key, value);
  • my_map.get(key)
  • my_map.has(key)
  • my_map.delete(key);
  • my_map.clear();
  • my_map.size;
  • my_map.forEach(function(value, key, ownerMap) {
    console.log(key + ” ” + value);
    console.log(ownerMap === map);
    });
  • let map = new WeakMap();

ES6: 符号类型

引入原因:

  • 实现私有属性
     
     
    let s = Symbol()
    let obj = {[s]: 'hello world'};
    console.log(obj.s); //undefined
  • 符号值唯一
     
     
    let s = Symbol()
    let m = Symbol()
    console.log(s === m)

创建:

  • 不能用字面量形式创建
  • 使用Symbol(desc)函数创建,不需要添加new
  • Symbol.for(key)在全局符号注册表中查找key符号值,如果找到就返回,没找到就创建一个新的符号值
  • Symbol.keyFor(symbol): 返回符号值的key

枚举:

  • 符号类型的key是不能被枚举的,Object.keys()以及Object.getOwnPropertyNames()都不能返回符号类型的key
  • Object.getOwnPropertySymbols()则会返回对象中所有符号类型的key

共享符号值:

  • Symbol.for(desc): 在全局符号注册表中查找描述为desc的符号,如果找到,返回这个符号值,如果没有,则创建一个新的符号值并返回
  • Symbol.keyFor(var): 返回全局符号注册表中符号值为var的desc.

转换:

  • 不能强制转化为字符串或者数值类型, 所以 symbol + “hello” 或者 symbol/1 会报错
  • 可以调用String()来转换

知名符号:

  • Symbol.hasInstance(obj): 判断obj是不是但前函数的实例,如Array[Symbol.hasInstance](obj); 可以通过以下代码改变instanceof的默认行为:
     
     
        Object.defineProperty(MyObject, Symbol.hasInstance, {
            value: function(v) {
                return false;
            }
        });
  • Symbol.isConcatSpreadable
     
     
    let collection = {
    0: "Hello",
    1: "world",
    length: 2,
    [Symbol.isConcatSpreadable]: true
    };
    let messages = [ "Hi" ].concat(collection);
    console.log(messages.length); // 3
    console.log(messages); // ["hi","Hello","world"]
  • Symbol.match 、 Symbol.replace 、 Symbol.search 、Symbol.split
  • Symbol.toPrimitive
     
     
    function Temperature(degrees) {
        this.degrees = degrees;
    }
    Temperature.prototype[Symbol.toPrimitive] = function(hint) {
        switch (hint) {
        case "string":
            return this.degrees + "\u00b0"; // 温度符号
        case "number":
            return this.degrees;
        case "default":
            return this.degrees + " degrees";
        }
    };
    let freezing = new Temperature(32);
    console.log(freezing + "!"); // "32 degrees!"
    console.log(freezing / 2); // 16
    console.log(String(freezing)); // "32°"
  • Symbol.toStringTag
     
     
    > age[Symbol.toStringTag] = 'Node';
    'Node'
    > age
    { age: 32,
    [Symbol(Symbol.toPrimitive)]: [Function],
    [Symbol(Symbol.toStringTag)]: 'Node' }
    > age.toString();
    '[object Node]'

ES6: 对象和数组解构

所谓解构,指的是将数据结构分解为更小的部分,从而使数据提取变得容易。

对象解构:

  • 使用解构时,必须提供初始化值

    [code lang=”js” collapse=”false”]
    let Person = {
    name: ‘sen’,
    age: 18
    }
    let {name, age} = Person;
    [/code]

  • 解构表达式的值为=右侧的值
  • 如果对象中没有同名属性时,解构表达式新赋值的变量的值为undefined
  • 解构对象只是赋值时,需要加()
  • 赋值给不同名的变量

    [code lang=”js” collapse=”false”]
    let Person = {
    name: ‘sen’,
    age: 18
    }
    let {name: localName, age: localAge} = Person;
    [/code]

  • 设置默认值

    [code lang=”js” collapse=”false”]
    let Person = {
    name: ‘sen’,
    age: 18
    }
    let {name, age: localAge = 18} = Person;
    [/code]

  • 嵌套解构

    [code lang=”js” collapse=”false”]
    let Person = {
    name: ‘sen’,
    age: 18,
    score: {
    maths: 100
    }
    }
    let {name, score: {maths}} = Person;
    console.log(maths);
    [/code]

数组解构

  • [code lang=”js” collapse=”false”]
    let score = [99, 88, 77];
    let [maths, english, chinese] = score;
    [,,chinese] = score;
    [/code]
  • 数组解构赋值不需要加()
    [code lang=”js” collapse=”false”]
    let a = 3;
    let b = 4;
    [a, b] = [b, a]
    [/code]
  • 嵌套的解构
    [code lang=”js” collapse=”false”]
    let score = [99, 88, [77]];
    let [,,[chinese]] = score;
    [/code]
  • 剩余项
    [code lang=”js” collapse=”false”]
    let score = [99, 88, 77];
    let [maths, …restScore] = score;
    console.log(restScore) // [88, 77]
    [/code]
  • 数组和对象可以混合解构
    [code lang=”js” collapse=”false”]
    let Person = {
    name: ‘sen’,
    age: [0, 18]
    }
    let {name: localName, age: [start]} = Person;
    console.log(start);
    [/code]

ES6: 对象扩展

  • 初始化简写:

    [code lang=”js” collapse=”false”]
    function createPerson(name, age) {
    return { name: name, age: age };
    }
    —&amp;amp;amp;amp;gt;
    function createPerson(name, age) {
    return { name, age };
    }

    [/code]

  • 方法简写:

    [code lang=”js” collapse=”false”]
    var person = {
    name: "sen",
    sayName: function() {
    return this.name;
    }
    }
    —&amp;amp;amp;gt;
    var person = {
    name: "sen",
    sayName() {
    return this.name;
    }
    }
    [/code]

  • 需要计算的属性名用[]表示
  • Object.is() 与===表现相同,除了
    Object.is(NaN, NaN) // true
    Object.is(+0, -0) // false
  • Object.assign(target, source) 将source中的属性和方法混入target对象
  • 允许重发的属性定义,排在最后的为实际值
  • 属性枚举的顺序:
    • 所有数字类型的键按升序排列
    • 所有字符串类型的键按添加进对象的顺序排列
    • 所有符号类型的键也按照添加进对象的顺序排列
  • 可修改对象的原型:
    Object.setPrototypeOf(obj, new_prototype)
  • 使用super作为指向原型对象的指针

ES6: 函数扩展

  • 带默认值的函数:var get_name = function(url, id=1, callback){};
    • 如果传入了第二个参数,将不会使用默认值
    • 如果给第二个参数赋值为undefined,会使用默认值
    • 带有默认值的参数后,arguments的内容将不会随着形参的改变而改变
    • 排在后面的参数可以将前面的参数作为默认值,而前面的参数不能引用后面的参数作为默认值
  • 剩余参数:var get_name = function(url, …keys)
    • 除了第一个参数url外,剩余所有参数都会被放到keys数组中
    • 函数只能有一个剩余参数,且必须放到最后
    • 剩余参数不能再对象字面量的setter属性中使用
  • 延展运算符:var args = [‘url’, 123, ‘st’]; get_names(…args);
  • new.target: 使用new创建一个对象时,会被赋值为新对象的构造器
  • ES6允许在代码块中定义函数,在严格模式中,块级函数只能在块级作用域中使用,而非严格模式中,块级函数会被提升到全局
  • 箭头函数
    • 没有this,super,arguments,new.target,这些值由所在的、最靠近的非箭头函数来决定
    • 不能使用new来调用
    • 没有原型
    • 不能更改this
    • 不允许有重复的具名参数
    • 语法
      • var reflect = value => value;
      • var sum = (num1, num2) => num1 + num2;
      • var getName = () => ‘Nicholas’;
      • var sum = (numb1, num2) => {return num1 + num2};
      • var doSomething = () => {};
      • var getItem = (id) => ({id: id, name: ‘Nicholas’});
      • var person = ((name) => {return {getName: function() {return name}};})(‘Nicholas’);
  • 尾调用优化:满足以下条件的尾调用将会被优化,在尾调用时不会创建新的栈帧,而是清除当前栈帧并再次利用它
    • 尾调用不能引用当前栈帧中的变量(意味着该函数不能是闭包)
    • 进行尾调用的函数在尾调用返回结果后不能做额外操作
    • 尾调用的结果作为当前函数的返回值

ES6: 字符串处理

UTF-16编码:

  • str.codePointAt(index)
  • String.fromCodePoint(codepoint);
  • normalize()

正则表达式

  • 新增u修饰符用来处理UTF-16编码的问题  /&.$/u
  • 新增pattern.flags 属性 // ‘ig’
  • 新增pattern.sticky 属性及’y’修饰符 // 只从lastIndex处匹配,如果和’g’一起存在则’g’被忽略
  • 复制正则表达式  // let pattern = new RegEX(old_pattern, ‘gi’)

字符串处理

  • str.includes(sub_string) // true or false
  • str.startsWith(sub_string)  // true or false
  • str.endsWith(sub_string) // true or false
  • str.repeat(times);  // str * times
  • 模板字面量
    • 支持多行字符串
    • 支持变量  // `hello ${name}`

Javascript中的表单

var form = document.getElementById(‘myform’);

  • form.acceptCharset 服务器能处理的字符集
  • form.action 接受请求的URL
  • form.elements 表单中的所有控件
  • form.enctype 编码类型
  • form.length 控件数量
  • form.method HTTP请求类型
  • form.name   // document.forms[form.name]
  • form.reset()
  • form.submit()
  • form.target

var text = form.elements[‘sex’];

  • text.disabled
  • text.form
  • text.name
  • text.value
  • text.readOnly
  • text.tabIndex
  • text.type
  • text.select()
  • text.setSelectionRange(start, end)
  • text.value.substring(text.selectionStart, text.selectionEnd)

text的事件:

  • change
  • focus
  • blur

剪贴板

var clipboard = window.clipboardData ; //event.clipboardData;

  • clipboard.getData()
  • clipboard.setData()
  • clipboard.clearData()

剪贴板事件

  • beforecopy
  • copy
  • beforecut
  • cut
  • beforepaste
  • paste

 

Javascript中的事件

事件捕获(capturing)和事件冒泡(bubbling)

添加事件处理程序的两种方法

  • <div onclick=”alert(‘ddd’)”></div>  // onclick=null
  • elem.addEventListener(“click”, e_func, false); //elem.removeEventListener(‘click’, e_func, false); //false 表明在冒泡阶段被触发

事件对象

  • e.bubbles // true or false 是否冒泡
  • e.cancelable // true of false 是否可取消默认行为
  • e.currentTarget // 正在处理事件的元素,事件处理程序中的this指向该元素
  • e.target // 事件发生的目标元素
  • e.defaultPrevented // true or false 默认行为是否被取消
  • e.detail
  • e.eventPhase // 1 捕获阶段 2 处于目标 3冒泡阶段
  • e.preventDefault()
  • e.stopImmediatePropagation() //阻止事件冒泡和所有事件处理程序
  • e.stopPropagation() //阻止事件冒泡
  • e.trusted // true 表示事件由浏览器生成,false表示有javascript触发
  • e.type
  • e.view
  • e.clientX e.clientY 事件发生时鼠标的视图位置
  • e.pageX e.pageY 事件发生时鼠标的页面位置
  • e.screenX e.screenY 事件发生时鼠标的屏幕位置
  • e.ctrlKey e.shiftKey e.altKey e.metaKey 事件发生时修饰键是否被按下
  • e.button // 0 主键 1 滚轮键 2右键 被按下
  • e.wheelDelta
  • e.charCode
  • e.keyCode
  • e.data //textinput 事件时输入的字符
  • e.iputMethod //0-9 输入来源,如键盘、粘贴、拖放等

事件类型

  • UI事件
    • load  (window, img)
    • unload
    • resize (window)
    • scroll (window)
  • 焦点事件
    • blur 失去焦点事触发,不会冒泡
    • focusin
    • focusout
    • focus 不会冒泡
  • 鼠标与滚轮事件
    • click
    • dbclick
    • mousedown 任何鼠标按键被按下时触发
    • mouseup
    • mouseenter 不冒泡
    • mouseover 冒泡
    • mousemove
    • mouseleave 不冒泡
    • mouseout 冒泡
    • mousewheel
    • contextmenu 鼠标右键弹出菜单
  • 键盘事件
    • keydown
    • keypress
    • keyup
    • textinput
  • DOM变动事件
    • DOMSubtreeModified
    • DOMNodeInserted
    • DOMNodeRemoved
    • DOMNodeInsertedIntoDocument
    • DOMNodeRemovedFromDocument
    • DOMAttrModified
    • DOMCharacterDataModified

事件委托和移除

为提升性能,利用事件冒泡来减少事件处理程序;在DOM元素被innerHTML移除后,需要手动的移除事件处理程序

事件模拟

  • var e = document.createEvent(‘MouseEvents’);
  • e.initMouseEvent(….);
  • elem.dispatchEvent(e);

DOM中的选择符API及元素遍历

选择符API

  • document.querySelector(css_selector)
    var checked_radio = document.querySelector(‘.checked’);
  • var node_list = document.querySelector(css_selector);
  • elem.matchesSelector(css_selector) // true or false

HTML 5中的类名操作

classList是DOMTokenList的实例,因而具有以下方法:

  • elem.classList.add(value); 如果已经有了就不添加了
  • elem.classList.contain(value) //true or false
  • elem.classList.remove(value)
  • elem.classList.toggle(value); 如果有就删除,如果没有就添加

 元素遍历

Element新增5个属性:

  • childElementCount: 子元素的个数(不包括Text和Comment类型)
  • firstElementChild
  • lastElementChild
  • previousElementSibling
  • nextElementSibling

Javascript中的DOM节点类型

Node类型

  • node.nodeType:
    • Node.ELEMENT_NODE(1);
    • Node.ATTRIBUTE_NODE(2);
    • Node.TEXT_NODE(3);
    • Node.CDATA_SECTION_NODE(4);
    • Node.ENTITY_PREFERENCE_NODE(5);
    • Node.ENTITY_NODE(6);
    • Node.PROCESSING_INSTRUCTION_NODE(7);
    • Node.COMMENT_NODE(8);
    • Node.DOCUMENT_NODE(9);
    • Node.DOCUMENT_TYPE_NODE(10);
    • Node.DOCUMENT_FRAGMENT_NODE(11);
    • Node.NOTATION_NODE(12);
  • node.nodeName: 标签名
  • node.childNodes[0]  node.childNodes.item(0);
  • node.childNodes.length;
  • node.parentNode;
  • node.nextSibling;
  • node.previousSibling;
  • node.firstChild;
  • node.lastChild;
  • node.appendChild(newNode);
  • node.insertBefore(newNode);
  • node.replaceChild(newNode, oldNode);
  • node.removeChild(node);
  • node.cloneNode(true//深复制)

HTMLDocument类型

  • document.nodeType = 9
  • document.nodeName = “#document”
  • document.nodeValue = null
  • document.parentNode = null
  • document.ownerDocument = null
  • document.firstChild === document.childNodes[0] === document.documentElement 都指向<html>元素
  • document.body指向<body>元素
  • document.head
  • document.charset
  • document.URL;
  • document.title;
  • document.domain;
  • document.getElementById();
  • document.getElementByClassName();
  • document.getElementsByTagName();
  • document.getElementsByName();
  • document.images;
  • document.anchors;
  • document.links;
  • document.forms;
  • document.createElement(‘div’)
  • document.activeElement: 指向获得焦点的元素
  • document.readyState // loading or complete

Element类型

var elem = document.getElementById(‘elem_id’);

  • elem.nodeType = 1
  • elem.nodeName 为元素的标签名
  • elem.nodeValue = null
  • elem.parentNode 为document或者Element
  • elem.nodeName === elem.tagName
  • elem.getAttribute(“id”)
  • elem.setAttribute(“id”, “new_id”)
  • elem.attributes.getNamedItem(‘id’)
  • elem.attributes.removeNamedItem(‘id’)
  • elem.attributes.setNamedItem(new_attr)
  • elem.getElementsByTagName()
  • elem.dataset // data- 前缀自定义的属性及属性值
  • elem.innerHTML // 元素的内容(所有子节点HTML)
  • elem.scrollIntoView() //将元素滚动至可见视图中
  • elem.style.width
  • elem.style

Text类型

<div>hello world</dev>

var text_node = div.firstChild;

var text_node = document.createTextNode(text);

  • text_node.nodeValue = text_node.data = ‘hello world’
  • text_node.appendData(‘string’);
  • text_node.deleteData(offset, count);
  • text_node.insertData(offset, text);
  • text_node.replaceData(offset, count, new_text);
  • text_node.splitText(offset);
  • text_node.substringData(offset);
  • text_node.length = text_node.data.length = text_node.nodeValue.length;
  • text_node.parentNode.normalize() // 将两个子文本节点合并

Comment类型

<div id=’mydiv’><!– comment –></div>

var mydiv = document.getElementById(‘mydiv’);

var comment = mydiv.firstChild;

var comment = document.createComment(‘comment’);

  • comment类型和Text类型继承自同一个基类,拥有除splitText之外Text的所有属性和方法

Attr类型

elem.attributes中的节点

var attr = document.createAttribute(attr_name);

  • attr.nodeType = 11
  • attr.nodeName 属性名
  • attr.nodeValue 属性值
  • attr.parentNode = null
  • elem.setAttributeNode(attr);

Javascript中的location对象

  • window.location === document.location // true
  • location的属性列表
  • 修改location的属性会导致页面刷新并产生新的历史记录
  • window.location = “URL” 和 location.href=”URL”效果一样,都会调用location.assign(URL)
  • location.replace(URL)不会产生新的历史记录,而且会禁用后退
  • location.reload(true): 重新加载页面,参数可以选择是否从服务器加载(而不是从缓存加载)

Javascript中的window对象

window对象的两个作用:

  • 表示浏览器的一个实例
  • ECMAscript中的Global对象
    直接定义Global变量与在window上定义Global变量的区别是:直接定义的Global变量的[[configurable]]特性为false,也就是说,它不能用delete删除

窗口关系及框架

  • 如果html中包含框架(frame),那么每个框架都有自己的window对象,它们从上到下,从左到右,依次存放于window.frames数组中。可以通过window.frames[index]或者window.frames[frame_name]来获取frame的window对象
  • window.name为frame的name
  • top对象表示最外层html的window对象
  • parent对象表示上层frame的window对象
  • self表示frame自身的window对象

窗口位置

  • window.screenLeft window.screenTop 或者firefox中的window.screenX window.screenY表示窗口左上角的位置
     
     
        var left = (typeof window.screenLeft == "number") ? window.screenLeft: window.screenX;
        var top = (typeof window.screenTop == "number") ? window.screenTop: window.screenY;
       
  • window.outerHight window.outerWidth 表示窗口的高和宽
  • window.innerHight window.innerWidth 表示页面视图的高和宽

打开新窗口

  • window.open(URL, target, args, is_replace)
    URL: 新窗口打开的网址
    target: 目标frame的名字,或者_self, _parent,_top,_blank
    args: is_replace: 是否替代当前窗口
  • window.close() : 关闭一个窗口
  • window.closed: 布尔值,window是否已经关闭
  • window.opener: 表示打开本窗口的窗口window对象

超时调用与间歇调用

  • var id = setTimeout(function, ms)  ; clearTimeout(id);
  • var id = setInterval(function, ms) ; clearInterval(id);

系统对话框

  • alert(‘string’)
  • var boolean = confirm(“string”);
  • var result_string = prompt(“string”, “default_answer”);

Javascript中的函数表达式

  • 函数声明 有提升 而函数表达式没有,因此不应该通过if…else来声明函数
     
     
        if (condition) {
            function sayHi() {}
        } else {
            function sayHi() {}
        }
       
  • 在递归函数中使用arguments.callee可以避免因函数名改变产生的错误。
     
     
        function factorial(num) {
            if (num 
                return 1;
            } else {
                return num * arguments.callee(num - 1);
            }
        }
       
  • 闭包是指函数中定义的函数,闭包的作用域链中包含父函数的执行环境(变量对象),所以即使父函数退出,如果闭包仍然被引用,那么父函数的变量对象就一直存在于内存中。所以,过度的使用闭包会导致内存占用过多
  • 闭包的另外一个副作用是闭包只能取得父函数中变量的最后一个值,例如:
     
     
        function createFunctions() {
            var result = new Array();
            for(var i = 0; i < 10; i++) {
                result[i] = function() {
                    return i;
                }
            }
            return result;
        }
       

    调用result中的每个函数都会返回10

  • 闭包如果是匿名函数,则该函数中的this指向全局对象
  • 可以用定义一个立即执行函数来模仿块级作用域:
     
     
            (function(){
            //块级作用域                                   
            })();                                        
       

Javascript中的对象

属性的类型

1.1 数据类属性

数据类属性的属性——特性为:

  • [[Configurable]]: 默认为true。表示能否通过delete删除属性,能否修改属性的特性。
  • [[Enumerable]]: 默认为true。表示在用for-in迭代对象时,能否迭代出该属性。
  • [[Writable]]: 默认为true。表示能否修改属性的值。
  • [[Value]]: 默认为undefined。保存属性的值。

1.2 访问器类属性

访问器类属性的特性为:

  • [[Configurable]]: 默认为true。表示能否通过delete删除属性,能否修改属性的特性。
  • [[Enumerable]]: 默认为true。表示在用for-in迭代对象时,能否迭代出该属性。
  • [[Get]]: 默认为undefined。读取属性时调用的函数。
  • [[Set]]: 默认为undefined。写入属性时调用的函数。

使用访问器类型的属性的常用方法是写入该属性时往往会导致其他属性也跟着变化。

 

1.3 对特性的操作方法:

Object.defineProperty(Object, propertyName, {attributes}): 设置属性的特性。
Object.defineProperties(Object, {propertyName: {attributes},}): 设置多个属性的特性。
Object.getOwnPropertyDescriptor(Object, propertyName);

 

创建对象的方法

2.1 工厂模式

 
 
function createPerson(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}
var sen = createPerson('sen', 19, 'programer');

缺点:无法识别一个对象属于哪一个类

 
 
alert(sen instanceof createPerson) // false

2.2 构造函数模式

 
 
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    this.sayName = function() {
        alert(this.name);
    }
}
var sen = new Person("sen", 19, "programer");
alert(sen instanceof Person) // true
alert(sen.constructor === Person) // true

缺点:每个对象都会有独立的函数定义

 
 
var sen1 = new Person("sen1", 19, "player");
alert(sen1.sayName == sen.sayName) // false

2.3 原型模式

 
 
function Person() {
}
Person.prototype.name = "sen";
Person.prototype.age = "19";
Person.prototype.job = "programer";
Person.prototype.sayName = fucntion() {
    alert(this.name);
}
var sen = new Person();
Person.prototype.constructor === Person // true
Person.prototype.isPrototypeOf(sen) // true
Object.getPrototypeOf(sen) === Person.prototype // true
sen.hasOwnProperty("name") // false
"name" in sen // true

判断属性是不是在原型对象中:

 
 
!sen.hasOwnProperty("name") && ("name" in sen)

原型模式更简洁的写法:

 
 
function Person(){};
Person.prototype = {
    constructor = Person,
    name: "sen",
    age: 19,
    job: "programer",
    sayName: function() {
        alert(this.name);
    }
}
Object.defineProperty(Person.prototype, {
    enumerable: false,
    value: Person
});

缺点:

1. 省略了传递初始化参数
2. 如果原型中的属性为引用类型,则所有对象会共用这个引用类型

2.4 组合使用构造模式和原型模式

 
 
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
}
Person.prototype.sayName = function() {
    alert(this.name)
}

缺点: 构造函数和原型是独立的

2.5 动态原型模式

 
 
function Person(name, age, job) {
    this.name = name;
    this.age = age;
    this.job = job;
    if (typeof this.sayName !== "function") {
        Person.prototype.sayName = function() {
            alert(this.name);
        };
    }
}

2.6 寄生构造函数模式

 
 
function Person(name, age, job) {
    var o = new Object();
    o.name = name;
    o.age = age;
    o.job = job;
    o.sayName = function() {
        alert(this.name);
    }
    return o;
}
var sen = new Person('sen', 19, 'programer');

寄生构造函数模式一般用于创建特殊的引用类型。例如,创建一个包含toPipedString方法的数组类型。

 
 
function SpecialArray() {
    var arr = new Array();
    arr.push.apply(arr, arguments);
    arr.toPipedString = function() {
        return this.join(" | ");
    }
    return arr;
}
var colors = new SpecialArray("red", "black");
alert(colors.toPipedString());

缺点和工厂模式一样,都无法被instanceof识别

2.7 稳妥构造函数模式

与寄生构造函数类似,区别在于:

  • 不使用this给类添加公共属性
  • 创建对象时不使用new关键字
 
 
  1. function Person(name, age, job) {
  2. var o = new Object();
  3. o.sayName = function() {
  4. alert(name);
  5. }
  6. return o;
  7. }
  8. var sen = Person('sen', 19, 'programer');

缺点和工厂模式一样,都无法被instanceof识别

继承

3.1 原型链

 
 
function SuperType() {
    this.property = true;
}
SuperType.prototype.getSuperValue = function() {
    return this.property;
}
function SubType() {
    this.subProperty = false;
}
SubType.prototype = new SuperType();
SubType.prototype.getSubValue = function() {
    return this.subProperty;
}
var obj = new SubType();
alert(obj instanceof SubType) // true
alert(obj instanceof SuperType) // true
alert(obj instanceof Object) // true

缺点:

  • SuperType中的属性如果为引用类型,所以的子类都会共用该属性
  • 创建子类时,如果给父类传递参数,会影响其他的子类

3.2 构造函数继承继承

 
 
function SuperType() {
    this.colors = ['black', 'red'];
}
function SubType() {
    SuperType.call(this);
}

缺点:函数无法复用

3.3 组合继承

 
 
function SuperType(name) {
    this.name = name;
    this.colors = ['black', 'red'];
}
SuperType.prototype.sayName = function() {
    return this.name;
}
function SubType(name) {
    SuperType.call(this, name);
}
SubType.prototype = new SuperType();

3.4 原型式继承

 
 
var person = {
    name: "sen"
}
var newPerson = Object.create(person, {name: {
    value: "yang"
}});

缺点: 原型式继承仅仅是对父类做了一个浅拷贝,并加入了子类自己的属性。所以问题和原型链相同,父类中的引用类型属性会被所有子类共用。

3.5 寄生式继承

 
 
function createAnother(obj) {
    var clone = Object.create(obj);
        clone.sayHi = function() {
        alert('hi');
    }
    return clone;
}

缺点: 函数不能复用

3.6 寄生组合式继承 (常用)

 
 
function inheritPrototype(subType, superType) {
    var prototype = Object.create(superType.prototype);
    prototype.constructor = subType;
    subType.prototype = prototype;
}
function SuperType(name) {
    this.name = name;
    this.colors = ['red', 'black'];
}
SuperType.prototype.sayName = function() {
    alert(this.name);
}
function SubType(name) {
    SuperType.call(this, name);
    this.age = age;
}
inheritPrototype(SubType, SuperType);

Javascript中的单体内置对象

Global

  1. encodeURI() encodeURIComponent(): 用utf-8编码替换URI中的无效字符,区别在于encodeURI并不对属于URI的特殊字符进行编码,如:// #?等
  2. eval(“var msg=’hello world'”); alert(msg);
  3. Global对象的属性:
    • undefined
    • NaN
    • Infinity
    • Object
    • Array
    • Function
    • Boolean
    • String
    • Number
    • Date
    • RegExp
    • Error
    • EvalError
    • RangeError
    • ReferenceError
    • SyntaxError
    • TypeError
    • URIError
  4. 可通过window对象来访问global对象的变量和函数
  5. var global = function(){return this;}();

Math

  • Math对象的属性:
    • Math.E
    • Math.LN10
    • Math.LN2
    • Math.LOG2E
    • Math.LOG10E
    • Math.PI
    • Math.SQRT1_2
    • Math.SQRT2
  • Math.min([1, 2, 3]) Math.max([1, 2, 3])
  • Math.ceil()
  • Math.floor()
  • Math.round()
  • Math.random():  [0-1)
  • Math.abs()
  • Math.exp()
  • Math.log()
  • Math.pow(num, power)
  • Math.sqrt()
  • Math.acos(x)
  • Math.asin(x)
  • Math.atan(x)
  • Math.atan2(y, x)
  • Math.cos(x)
  • Math.sin(x)
  • Math.tan(x)

Javascript中的基本包装类型

当读取一个基本类型(Boolean、String、Number)的值时,后台对创建一个对应的基本包装类型,从而让我们可以调用一些方法来操作这些数据。

基本包装类型与引用类型的区别:

  • 生存期。自动创建的包装类型只存在于一行代码存在的瞬间。不能在运行时为基本类型添加属性和方法。

Number类型常用的方法

  • toString()
  • toFixed(2) //小数点后两位
  • toExponential()
  • toPrecision(3)

String类型常用的属性和方法

  • length: 返回字符串的长度
  • charAt(2) charCodeAt(2): 返回字符串中第三个字符/编码
  • concat(“xxx”) 或者 + “xxx”: 字符串拼接
  • slice(start, end) subString(start, end) subStr(start, number): 字符串切片
    当start为负值时,slice和subStr会把它与字符串长度相加得到新的start;而subString则会将其转化为0
    当end/number为负值时,slice会把它与字符串长度相加得到新的end,subStr和subString会将其转化为0
  • indexOf(‘d’, start) 和lastIndexOf(‘d’, start): 从start位置开始向左(右)查找’d’在字符串中的位置
  • trim(): 返回删除字符串左右的空格的新字符串
  • trimLeft() trimRight(): 返回删除字符串左(右)的空格的新字符串
  • toLowerCase() toLocaleLowerCase() toUpperCase() toLocaleUpperCase()
  • match(pattern/RegExp): 返回的数组与RegExp.exec相同
  • search(pattern/RegExp): 返回匹配到的位置
  • replace(old, new):
    如果old为字符串时,仅替换该字符串;如果Old是带’g’标志的pattern时,会替换所有匹配的字符串
    new字符串中可以是下列特殊序列:
    $$: $
    $&: 等价于RegExp.lastMatch
    $’: RegExp.leftContext
    $`: RegExp.rightContext
    $n $nn: 第n个捕获组匹配到的字符串
    new可以是一个函数:function(match, pos, orignialText){return string}
  • var array = “string”.split(‘string/pattern’, number)
"