作用域

词法作用域:编译阶段确定(欺骗词法作用域 eval with)

function foo(str){
"use strict"
eval(str)
console.log(a)
}
foo('var a = 2')
function foo(obj){
with (obj){
a = 2
}
}
var o1 = {a:3}
var o2 = {b:3}
foo(o1)
foo(o2)

块作用域 with try/catch let const

for (let i=0; i<10; i++){
console.log(i)
}
if (true) {
var a = 1
let b = 2
const c = 3
}
console.log(a) // 1
console.log(b) // ReferenceError
console.log(c) // ReferenceError
try{throw 2}catch(a){
console.log(a) // 2
}
console.log(a) // ReferenceError

提升

定义提升 函数优先

foo() // TypeError
bar() // ReferenceError
var foo = function bar(){}
foo() // 1
function foo(){
console.log(1)
}
foo = function(){
console.log(2)
}
foo() // 3
function foo(){
console.log(1)
}
foo = function(){
console.log(2)
}
function foo(){
console.log(3)
}
foo() // 2
if (true){
function foo(){console.log(1)}
}else{
function foo(){console.log(2)}
}

闭包

将内部函数传递到所在作用域以外,它都会持有对原始定义作用域的引用,无论何处执行这个函数都会使用闭包。

function foo(){
setTimeout(function a(){})
}
function foo(){
return function a(){}
}
var b = foo()
b()
var b = (function(){
function foo(){}
}())
b.foo()

循环+闭包

for (var i=0; i<5; i++){
setTimeout(function(){
console.log(i) // 5
})
}
for (var i=0; i<5; i++){
var j = i
setTimeout(function(){
console.log(j) // 4
})
}
for (var i=0; i<5; i++){
(function(){
var j = i
setTimeout(function(){
console.log(j) // 0 1 2 3 4
})
})()
}
for (let i=0; i<5; i++){
setTimeout(function(){
console.log(i) // 0 1 2 3 4
})
}
for (var i=0; i<5; i++){
let j = i
setTimeout(function(){
console.log(j) // 4
})
}
for (var i=0; i<5; i++){
(function(j){
setTimeout(function(){
console.log(j) // 0 1 2 3 4
})
})(i)
}

模块机制闭包的作用

var require = (function(name){
var modules = {}
function define(name, deps, impl) {
for (var i=0; i<deps.length; i++){
deps[i] = modules[deps[i]]
}
modules[name] = impl.apply(impl, deps)
}
function get(name) {
return modules[name]
}
console.log(name)
return {
define: define,
get: get
}
}())
require.define('foo', [], function(){
return {
hello: function() {console.log('hello world')},
name:'foo'
}
})
require.define('bar', ['foo'], function(foo){
return {
hello: function() {console.log('bar:' + foo.name)},
name: 'bar'
}
})
require.define('user', ['foo', 'bar'], function(foo, bar){
return {
hello: function() {console.log('user:' + foo.name +', ' + bar.name)}
}
})
var foo = require.get('foo')
var bar = require.get('bar')
var user = require.get('user')
foo.hello()
bar.hello()
user.hello()

This

默认绑定 隐式绑定 显式绑定(硬绑定 call apply bind) new绑定

默认绑定

function foo(){
console.log(this.count) // 1
console.log(foo.count) // 2
}
var count = 1
foo.count = 2
foo()
严格模式this不会绑定到window
function foo(){
"use strict"
console.log(this.count) // TypeError: count undefined
}
var count = 1
foo()

隐式绑定

function foo(){
console.log(this.count) // 2
}
var obj = {
count: 2,
foo: foo
}
obj.foo()

别名丢失隐式绑定

function foo(){
console.log(this.count) // 1
}
var count = 1
var obj = {
count: 2,
foo: foo
}
var bar = obj.foo // 函数别名
bar()

回调丢失隐式绑定

function foo(){
console.log(this.count) // 1
}
var count = 1
var obj = {
count: 2,
foo: foo
}
setTimeout(obj.foo)

显式绑定

function foo(){
console.log(this.count) // 1
}
var obj = {
count: 1
}
foo.call(obj) var bar = foo.bind(obj)
bar()

new绑定

function foo(a){
this.a = a
}
var bar = new foo(2)
console.log(bar.a) // 2

this丢失

function foo(){
setTimeout(function() {
console.log(this.count) // undefined
})
}
var obj = {
count: 2
}
foo.call(obj)

局部变量修复

function foo(){
var self = this
setTimeout(function() {
console.log(self.count) // 2
})
}
var obj = {
count: 2
}
foo.call(obj)

bind修复

function foo(){
setTimeout(function() {
console.log(this.count) // 2
}.bind(this))
}
var obj = {
count: 2
}
foo.call(obj)

es6绑定

function foo(){
setTimeout(() => {
console.log(this.count) // 2
})
}
var obj = {
count: 2
}
foo.call(obj)

对象

类型 string number boolean null undefined object

对象 String Number Boolean Object Function Array Date RegExp Error

var str = 'hello world'
var strObj = new String('hello world')
console.log(strObj.length) // 11
console.log(str.length) // 11 (string -> new String)

属性描述符ES5

var obj = {
a: 2
}
Object.getOwnPropertyDescriptor(obj, 'a') // {value: 2, writable: true, enumerable: true, configurable: true}

可写

var obj = {}
Object.defineProperty(obj, 'a', {
value: 2,
writable: false
})
obj.a = 3
console.log(obj.a) // 2 严格模式TypeError

可枚举

var obj = {b: 1}
Object.defineProperty(obj, 'a', {
value: 2,
enumerable: false
})
for (var key in obj){
console.log(key) // b
}

可配置(不可配置:不能删除,能修改)

var obj = {}
Object.defineProperty(obj, 'a', {
value: 2,
configurable: false
})
delete obj.a
console.log(obj.a) // 2

禁止拓展属性

var obj = {}
Object.preventExtensions(obj)
obj.a = 3
console.log(obj.a) // undefined

密封(禁止拓展属性+不可配置)(preventExtensions+each(configurable: false))

var obj = {}
Object.seal(obj)

冻结(密封+不可修改属性值)(seal+each(writable:false))

var obj = {}
Object.freeze(obj)

[[get]]获取对象属性会执行[[get]]操作,自身没有的属性会在原型链上查找,都没有返回undefined

var obj = {}
console.log(obj.a) // undefined
console.log(a) // ReferenceError

[[put]] 对象赋值触发[[put]],在赋值前会检查对象属性描述,例如不可写会失败

var obj = {
a: 1
}
Object.defineProperty(obj, 'a', {
writable: false
})
obj.a = 2
console.log(obj.a) // 1

[[put]] 自身存在setter方法,会优先调用setter,如果原型链上有同名setter,会调用原型链的setter

var obj = {
a: 1,
set a(val){
console.log('nothing happend')
}
}
obj.a = 2
console.log(obj.a) // undefined set方法会覆盖同名属性

getter

var obj = {
get a(){
return 1
}
}
console.log(obj.a) // 1

setter 一般使用_property_表示屏蔽属性

var obj = {
set a(val){
_a_ = val*2
},
get a(){
return _a_ - 1
}
}
obj.a = 2
console.log(obj.a) // 3

js没有类(继承是复制,js某些部分是引用)

类是一种设计模式,可以被模拟:混入

// 显式混入 ($.extend)
function mixin(sourceObj, targetObj) {
for (var key in sourceObj) {
if (!(key in targetObj)) { // 重名不覆盖,实现多态
targetObj[key] = sourceObj[key]
}
}
return targetObj
} var obj = {
a: 1,
b: function(){console.log(2)}
} var child = mixin(obj, {
c:3
}) console.log(child.b.prototype) // obj.b {}
// 隐式混入
var obj = {
add: function() {
this.count = this.count ? this.count+1 : 1
}
} var child = {
add: function() {
obj.add.call(this)
}
} obj.add()
console.log(obj.count) // 1
child.add()
console.log(child.count) // 2 隐式混入赋值操作在child而不是obj
// 寄生继承(既是显示又是隐式)
function obj(){
this.a = 1
}
function child(){
var o= new obj()
o.b = 2
return o
}
var c = new child()
console.log(c.b) //2

原型

prototype

// 原型的设置和屏蔽
var foo = {
a: 1
}
var bar = Object.create(foo)
console.log(bar.hasOwnProperty('a')) // false 原型设置
bar.a++
console.log(bar.hasOwnProperty('a')) // true 原型被屏蔽
// 设置原型链
// 直接设置原型
function foo(){this.a = 1}
foo.prototype.b = 2
function bar(){}
bar.prototype = foo.prototype // bar.prototype: foo {}
var b = new bar()
console.log(b.a) // undefined
console.log(b.b) // 2 // 无副作用设置原型链
function foo(){this.a = 1}
foo.prototype.b = 2
function bar(){}
bar.prototype = Object.create(foo.prototype) // bar.prototype: object {}
var b = new bar()
console.log(b.a) // undefined
console.log(b.b) // 2 // ES6可以不抛弃原型直接赋值
Object.setPrototypeOf(var.prototype, foo.prototype) // 常见用法但有调用构造方法的副作用
function foo(){this.a = 1}
foo.prototype.b = 2
function bar(){}
bar.prototype = new foo()
var b = new bar()
console.log(b.a) // 1 副作用:执行了构造函数
console.log(b.b) // 2
// 判断类关系
function foo(){}
var f = new foo()
console.log(f instanceof foo) // true
console.log(foo.prototype.isPrototypeOf(f)) // true
// 如何获取原型
function foo(){}
var a = new foo() console.log(Object.getPrototypeOf(a) === foo.prototype) // true
// __proto__ 可以获取原型的原因
Object.defineProperty(Object.prototype, '__proto__', {
get: function(){
return Object.getPrototypeOf(this)
},
set: function(o){
Object.setPrototype(this, o)
return o
}
})

行为委托

行为委托是除了类之外,更清晰的一种继承设计模式

// 类创建实例
function Foo(){
this.something = function(){}
}
var bar = new Foo()
bar.something()
// 委托创建实例 ES5
var foo = {
something: function(){}
}
var bar = Object.create(foo) // foo 自身也是个实例
bar.something()
// Object.create模拟
if (!Object.create){
Object.create = function(obj){
function F(){}
F.prototype = obj
return new F()
}
}
// 类的继承
function Foo(){}
Foo.prototype.say = function(){console.log(1)} function Bar(){}
Bar.prototype = Object.create(Foo.prototype) // 或 new Foo() var b = new Bar()
b.say() // 1
// 对象关联的继承
var Foo = {
say: function(){console.log(1)}
}
var Bar = Object.create(Foo) var b = Object.create(Bar) // 或 new Bar()
b.say() // 1

你不知道的 Javascript的更多相关文章

  1. 《你不知道的JavaScript》整理(二)——this

    最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,这次研究了一下“this”. 当一个函数被调用时,会创建一个活动记录(执行上下文). 这个记录会包含函 ...

  2. 《你不知道的JavaScript》整理(一)——作用域、提升与闭包

    最近在读一本进阶的JavaScript的书<你不知道的JavaScript(上卷)>,里面分析了很多基础性的概念. 可以更全面深入的理解JavaScript深层面的知识点. 一.函数作用域 ...

  3. 你不知道的Javascript(上卷)读书笔记之一 ---- 作用域

    你不知道的Javascript(上卷)这本书在我看来是一本还不错的书籍,这本书用比较简洁的语言来描述Js的那些"坑",在这里写一些博客记录一下笔记以便消化吸收. 1 编译原理 在此 ...

  4. 你不知道的JavaScript上卷笔记

    你不知道的JavaScript上卷笔记 前言 You don't know JavaScript是github上一个系列文章   初看到这一标题的时候,感觉怎么老外也搞标题党,用这种冲突性比较强的题目 ...

  5. 【读书笔记】-- 你不知道的JavaScript

    <你不知道的JavaScript>是一个不错的JavaScript系列书,书名可能有些标题党的意思,但实符其名,很多地方会让你有耳目一新的感觉. 1.typeof null === &qu ...

  6. 读书笔记-你不知道的JavaScript(上)

    本文首发在我的个人博客:http://muyunyun.cn/ <你不知道的JavaScript>系列丛书给出了很多颠覆以往对JavaScript认知的点, 读完上卷,受益匪浅,于是对其精 ...

  7. 读《你不知道的JavaScript(上卷)》后感-作用域闭包(二)

    github原文 一. 序言 最近我在读一本书:<你不知道的JavaScript>,这书分为上中卷,内容非常丰富,认真细读,能学到非常多JavaScript的知识点,希望广大的前端同胞们, ...

  8. 你不知道的javaScript上卷(第一章 作用域是什么)

    在写这篇博客时这本书我已经是看过一遍了,为了加深印象和深入学习于是打算做这系列的前端经典书籍导读博文,大家如果觉得这本书讲的好可以自己买来看看,我是比较喜欢看纸质版书的,因为这样才有读书的那种感觉. ...

  9. JavaScript中的this(你不知道的JavaScript)

    JavaScript中的this,刚接触JavaScript时大家都在大肆渲染说其多么多么的灵巧重要,然而自己并不关心:随着自己对JavaScript一步步深入了解,突然恍然大悟,原来它真的很重要!所 ...

  10. 你不知道的Javascript:有趣的setTimeout

    你不知道的Javascript:有趣的setTimeout 有时候,小小的细节往往隐藏着大大的智慧今天在回顾JavaScript进阶用法的时候,发现一个有趣的问题,话不多说,先上代码: for(var ...

随机推荐

  1. 在Linux运行期间升级Linux系统(Uboot+kernel+Rootfs)

    版本:v1.2   Crifan Li 摘要 本文主要介绍了如何在嵌入式Linux系统运行的时候,进行升级整个Linux系统,包括uboot,kernel和rootfs.以及简介Linux中的已有的通 ...

  2. Timus 1746 Hyperrook

    题意:在一个n维坐标系中,坐标的范围是0到m - 1,如果两个点坐标只有一个维度的坐标不同则可以相互移动,给出p个点,问任意两个点之间路径为d的个数是多少,答案与p取模. 解法:只需要考虑两个点之间不 ...

  3. Java中调用参数是数组的存储过程

    Java中调用参数是数组的存储过程 1. 存储过程以及类型定义如下: --The array in oracle CREATE OR REPLACE TYPE idArray AS TABLE OF ...

  4. Myeclipse *.link用法

    引用路径 path=D:\\ProgramData\\MyEclipse\\adt

  5. CSLA的项目结构(一)

    由于我也是边看边学,在很多概念不是很清晰的情况下,也不好将书中的大段内容全部摘抄过来,所以结合项目源码先分析再总结,就成目前比较可行方案,第一篇先从项目结构入手. 项目源码下载后,主要的功能集中在Co ...

  6. NOIP2014 飞扬的小鸟

    3. 飞扬的小鸟 (bird.cpp/c/pas) [问题描述] Flappy Bird 是一款风靡一时的休闲手机游戏.玩家需要不断控制点击手机屏幕的频率来调节小鸟的飞行高度,让小鸟顺利通过画面右方的 ...

  7. hdu4777-Rabbit Kingdom

    题意:求区间内与其他任何数都互质的数的个数. 题解:求出每个数左右互质的边界.然后对询问排序,通过树状数组求解. 讲道理真的好难啊= = http://blog.csdn.net/dyx404514/ ...

  8. Android实例-操作sqlite数据之自建导航(XE8+小米2)

    相关资料: 源文:http://blog.sina.com.cn/s/blog_77691fb90101g9hh.html help://embarcadero.rs_xe5/rad/Mobile_T ...

  9. Codeforces Wilbur and Array

    Description Wilbur the pig is tinkering with arrays again. He has the array a1, a2, ..., an initiall ...

  10. 转载Expression Tree揭秘

    概述 在.NET Framework 3.5中提供了LINQ 支持后,LINQ就以其强大而优雅的编程方式赢得了开发人员的喜爱,而各种LINQ Provider更是满天飞,如LINQ to NHiber ...