你不知道的js

作用域 LHS RHS 区别

  1. 如果 RHS 查询在所有嵌套的作用域中遍寻不到所需的变量,引擎就会抛出 ReferenceError 异常。值得注意的是,ReferenceError 是非常重要的异常类型。
    相较之下,当引擎执行 LHS 查询时,如果在顶层(全局作用域)中也无法找到目标变量,
    全局作用域中就会创建一个具有该名称的变量,并将其返还给引擎,前提是程序运行在非 “严格模式”下。

  2. ReferenceError 同作用域判别失败相关,而 TypeError 则代表作用域判别成功了,但是对 结果的操作是非法或不合理的。

  3. 在严格模式的程序中,eval(..) 在运行时有其自己的词法作用域,意味着其 中的声明无法修改所在的作用域

  4. 使用 let 进行的声明不会在块作用域中进行提升
    变量和函数声明从它们在代码中出现的位置被“移动”到了最上面。这个过程就叫作提升。
    只有声明本身会被提升,而赋值或其他运行逻辑会留在原地.并且函数会优先提升.

5.词法作用域和动态作用域的区别. 好在 javascript并不具有动态作用域.
主要区别:词法作用域是在写代码或者说定义时确定的,而动态作用域是在运行时确定的。
词法作用域关注函数在何处声明,而动态作用域关注函数从何处调用。

this和对象原型

this的绑定规则

  1. 默认绑定.
    独立调用函数时,会默认绑定到全局对象. 严格模式下,全局对象无法使用默认绑定,因此this会绑定到undefined
    注意: nodejs环境下的this指向的是 module.exports,默认为{}
    但是函数中默认的this,指向的是 global 对象.

  2. 隐式绑定
    函数调用的位置有上下文对象,this会绑定到这个上下文对象.
    主要注意的是要小心隐式丢失.

  3. 显式绑定
    call apply 方法
    bind 方法

  4. new 绑定

优先级是 4 > 3 > 2 > 1

javsscript里面的类型

  1. 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

  1. 内置对象
    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 没有对应的构造形式.

  1. 属性
    在对象中,属性名永远都是字符串。如果你使用 string(字面量)以外的其他值作为属性 名,那它首先会被转换为一个字符串。即使是数字也不例外,虽然在数组下标中使用的的 确是数字,但是在对象属性名中数字会被转换成字符串,所以当心不要搞混对象和数组中 数字的用法.

es6添加了可计算属性名,可以在文字形式中使用[]包裹一个表达式来当作属性名.

var prefix = "foo";
var myObject = {
    [prefix + "bar"]:"hello", 
    [prefix + "baz"]: "world"
};
myObject["foobar"]; // hello
myObject["foobaz"]; // world

Object.assign 只会进行浅拷贝.

  1. 属性描述符
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 这个方法可以判断属性名是否可枚举,并且不会检查原型链

  1. 属性不变性

a. 将属性的 writabel 和 configurable 都设置成false即可.
那么这个属性就不可被修改和重定义或者删除.

b. 禁止扩展
Object.preventExtensions(..); 只是不能添加新的属性,但是可以修改属性的值,
还可以删除属性.

c. 密封
Object.seal(..), 这个方法会调用Object.preventExtensions,然后将现有属性的configurable设置成false.
但是可以修改属性的值,不能删除属性.

d.冻结
Object.freeze(..),
这个方法实际会调用Object.seal(),并且把所有的属性的writable设置成false, 这是最高级别的不变性.

  1. [[Get]]/[[Put]]
    set get的定义.

  2. 存在性
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 的对象.

混合对象"类"

  1. 显示混入
function mixin(sourceObj,targetObj){
    for(let k in sourceObj){
        if(!(k in targetObj)){
            targetObj[k] = sourceObj[k];
        }
    }
    return targetObj;
};

这种是浅复制,如果有数组或者对象或者函数(函数也是对象),则会同时影响sourceObj和targetObj.

  1. 寄生继承

  2. 隐式混入

  3. 原型链 属性屏蔽
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 来调用函数,或者说发生构造函数调用时,会自动执行下面的操作。

  1. 创建(或者说构造)一个全新的对象。
  2. 这个新对象会被执行[[原型]]连接。
  3. 这个新对象会绑定到函数调用的this。
  4. 如果函数没有返回其他对象,那么new表达式中的函数调用会自动返回这个新对象。

猜你喜欢

转载自www.cnblogs.com/daihanlong/p/9972716.html