作用域 LHS RHS 区别
-
如果 RHS 查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError 异常。值得注意的是,ReferenceError 是非常重要的异常类型。
相较之下,当引擎执行 LHS 查询时,如果在顶层(全局作用域)中也无法找到目标变量,
全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非 “严格模式”下。 -
ReferenceError 同作用域判别失败相关,而 TypeError 则代表作用域判别成功了,但是对 结果的操作是非法或不合理的。
-
在严格模式的程序中,eval(..) 在运行时有其自己的词法作用域,意味着其 中的声明无法修改所在的作用域
-
使用 let 进行的声明不会在块作用域中进行提升
变量和函数声明从它们在代码中出现的位置被“移动”到了最上面。这个过程就叫作提升。
只有声明本身会被提升,而赋值或其他运行逻辑会留在原地.并且函数会优先提升.
5.词法作用域和动态作用域的区别. 好在 javascript并不具有动态作用域.
主要区别:词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的。
词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。
this和对象原型
this的绑定规则
-
默认绑定.
独立调用函数时,会默认绑定到全局对象. 严格模式下,全局对象无法使用默认绑定,因此this会绑定到undefined
注意: nodejs环境下的this指向的是 module.exports,默认为{}
但是函数中默认的this,指向的是 global 对象. -
隐式绑定
函数调用的位置有上下文对象,this会绑定到这个上下文对象.
主要注意的是要小心隐式丢失. -
显式绑定
call apply 方法
bind 方法 -
new 绑定
优先级是 4 > 3 > 2 > 1
javsscript里面的类型
- js有7种内置类型
string number boolean undefined object null symbol
typeof 'aaa' // string
typeof 3 // number
typeof true // boolean
typeof undefined //undefined
let a = {};
typeof a // object
注意:
typeof null // object
let func = function(){}
typeof func // function
- 内置对象
String Number Boolean Object Function Array Date RegExp Error
其实只是一些内置函数.
注意基本类型和这些内置对象的区别,如:
let str = 'I am a string'; // 又叫字符串字面量
typeof str; // string
str instanceof String; // false
let str2 = new String('I am a string');
typeof str2; // object
str2 instanceof String; // true
检查上面这些内置对象的方法:
Object.prototype.toString.call(str2); // [object String]
如下代码会自动把字面量转换成String对象,所以可以访问属性和方法.
let str = 'I am a string';
console.log(str.length);
console.log(str.charAt(3)); // 'm'
string 对应的构造形式 String
number 对应的构造形式 Number
boolean 对应的构造形式 Boolean
null 和 undefined 没有对应的构造形式.
- 属性
在对象中,属性名永远都是字符串。如果你使用 string(字面量)以外的其他值作为属性 名,那它首先会被转换为一个字符串。即使是数字也不例外,虽然在数组下标中使用的的 确是数字,但是在对象属性名中数字会被转换成字符串,所以当心不要搞混对象和数组中 数字的用法.
es6添加了可计算属性名,可以在文字形式中使用[]包裹一个表达式来当作属性名.
var prefix = "foo";
var myObject = {
[prefix + "bar"]:"hello",
[prefix + "baz"]: "world"
};
myObject["foobar"]; // hello
myObject["foobaz"]; // world
Object.assign 只会进行浅拷贝.
- 属性描述符
var myObject = {
a:2
};
let pd = Object.getOwnPropertyDescriptor( myObject, "a" );
// pd:
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }
使用 Object.defineProperty(..)来添加一个新的属性或者修改一个已有的属性.
a. writable
如果设置成 false,则不能修改值了.
b. configurable
如何 configurable 为false, 则后面就不能将这个属性的 configurable 设置成true了,
并且这个属性也不能被删除. 但是可以被修改.
同时, 只能将 writable 的状态从 true改成false,不能由 false 改成 true.
c. enumerable
设置成false,则不会出现在for..in循环中. 但是还是可以正常访问.
propertyIsEnumerable 这个方法可以判断属性名是否可枚举,并且不会检查原型链
- 属性不变性
a. 将属性的 writabel 和 configurable 都设置成false即可.
那么这个属性就不可被修改和重定义或者删除.
b. 禁止扩展
Object.preventExtensions(..); 只是不能添加新的属性,但是可以修改属性的值,
还可以删除属性.
c. 密封
Object.seal(..), 这个方法会调用Object.preventExtensions,然后将现有属性的configurable设置成false.
但是可以修改属性的值,不能删除属性.
d.冻结
Object.freeze(..),
这个方法实际会调用Object.seal(),并且把所有的属性的writable设置成false, 这是最高级别的不变性.
-
[[Get]]/[[Put]]
set get的定义. -
存在性
var myObject = {
a:2
};
("a" in myObject); // true
("b" in myObject); // false
myObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "b" ); // false
in 操作符会检查属性是否在对象及其原型链中(不管枚举属性是否为true,都会判断).
hasOwnProperty 则不会检查原型链.
Object.keys(..) 会返回一个数组,包含所有可枚举属性,
Object.getOwnPropertyNames(..) 会返回一个数组,包含所有属性,无论它们是否可枚举。
in 和 hasOwnProperty(..) 的区别在于是否查找 [[Prototype]] 链,
然而,Object.keys(..) 和 Object.getOwnPropertyNames(..) 都只会查找对象直接包含的属性。
8.遍历
for..in 用来遍历对象的可枚举属性(包含原型链,要求枚举属性必须为true,注意和 in 操作符的区别).
但是如果要遍历值,则使用 foreach every some 等.
es6 的 for..of 可以用来遍历数组的值.
for..of 还可以用来遍历实现了 iterator 的对象.
混合对象"类"
- 显示混入
function mixin(sourceObj,targetObj){
for(let k in sourceObj){
if(!(k in targetObj)){
targetObj[k] = sourceObj[k];
}
}
return targetObj;
};
这种是浅复制,如果有数组或者对象或者函数(函数也是对象),则会同时影响sourceObj和targetObj.
-
寄生继承
-
隐式混入
-
原型链 属性屏蔽
let another = { a : 2};
let myobj = Object.create(another);
console.log(myobj); // {}
console.log(myobj.hasOwnProperty("a")); // false
myobj.a = 5;
console.log(myobj.hasOwnProperty("a")); // true
console.log(myobj); {a:5}
属性屏蔽规则:
如:myobj.a = 5;
a.如果myobj包含a属性,则不管原型链上是否有a属性, 都会直接应用到myobj对象上,而不会影响原型链上的a.
b.如果myobj本身不包含a属性,则会遍历原型链,如果原型链上也没有a属性,则a会被添加到myobj对象上.
c.如果myobj本身不包含a属性,但是原型链上有a属性,并且a属性的 writable为true,则会直接添加到myobj对象上,但是不会影响原型链上的a(属性屏蔽),如果原型链上的a属性的writable为false,非严格模式下不会产生效果,严格模式下报错.
d.如果myobj本身不包含a属性,但是原型链上a是一个setter,则会调用这个setter,而a属性不会被添加myobj上.
总结: 如果要给myobj添加a的属性去屏蔽原型链上的属性a, 则使用Object.defineProperty(..)
注意 隐式屏蔽. 如:
myobj.a++,相当于 myobj.a = myobj.a + 1;
类
function Foo(){}
let foo = new Foo();
使用 new 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。
- 创建(或者说构造)一个全新的对象。
- 这个新对象会被执行[[原型]]连接。
- 这个新对象会绑定到函数调用的this。
- 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。